fcached.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. // Prints OS cached details for files open by a process
  14. #include "platform.h"
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #include <stdio.h>
  18. #include <dirent.h>
  19. #include <dirent.h>
  20. #include <sys/vfs.h>
  21. #include <sys/mman.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <time.h>
  25. #include "ctfile.hpp"
  26. static char *_itoa(unsigned long n, char *str, int b, bool sign)
  27. {
  28. char *s = str;
  29. if (sign)
  30. n = -n;
  31. do
  32. {
  33. byte d = n % b;
  34. *(s++) = d+((d<10)?'0':('a'-10));
  35. }
  36. while ((n /= b) > 0);
  37. if (sign)
  38. *(s++) = '-';
  39. *s = '\0';
  40. // reverse
  41. char *s2 = str;
  42. s--;
  43. while (s2<s)
  44. {
  45. char tc = *s2;
  46. *(s2++) = *s;
  47. *(s--) = tc;
  48. }
  49. return str;
  50. }
  51. char *itoa(int n, char *str, int b)
  52. {
  53. return _itoa(n, str, b, (n<0));
  54. }
  55. size_t page_size;
  56. inline offset_t pagetoofs(unsigned pg)
  57. {
  58. return (offset_t)page_size*(offset_t)pg;
  59. }
  60. void nodeStats(int fd,offset_t ofs,unsigned &leaves,unsigned &nonleaves)
  61. {
  62. _lseeki64(fd, ofs, SEEK_SET);
  63. NodeHdr hdr;
  64. if (_read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
  65. printf("ERROR: Could not read node at %" I64F "x", ofs);
  66. return;
  67. }
  68. if (hdr.leafFlag)
  69. leaves++;
  70. else
  71. nonleaves++;
  72. }
  73. void printFileCache(const char *fname, unsigned &globtot, unsigned &globfs, bool verbose, bool onlykey, unsigned &totlf, unsigned &totnl)
  74. {
  75. if (onlykey&&(strstr(fname,"_of_")==NULL))
  76. return;
  77. size_t page_index;
  78. unsigned leaves=0;
  79. unsigned nonleaves=0;
  80. int fd = open(fname,O_RDONLY);
  81. if (fd==-1) {
  82. int err = errno;
  83. if (err==ENOENT)
  84. return;
  85. printf("ERROR: open %s failed %d\n",fname,err);
  86. return;
  87. }
  88. struct stat file_stat;
  89. fstat(fd, &file_stat);
  90. if (!S_ISREG(file_stat.st_mode))
  91. return;
  92. void * file_mmap = mmap((void *)0, file_stat.st_size, PROT_NONE, MAP_SHARED, fd, 0);
  93. page_size = getpagesize();
  94. unsigned fs = (file_stat.st_size+page_size-1)/page_size;
  95. if (!fs)
  96. return;
  97. unsigned char *mincore_vec = (unsigned char *)calloc(1, fs);
  98. mincore(file_mmap, file_stat.st_size, mincore_vec);
  99. printf("%s:\n",fname);
  100. size_t s = 0;
  101. size_t e = (size_t)-1;
  102. unsigned tot = 0;
  103. for (size_t page_index = 0; page_index < fs; page_index++) {
  104. if (mincore_vec[page_index]&1) {
  105. if (page_index&&onlykey&&(pagetoofs(page_index)%8192==0))
  106. nodeStats(fd,pagetoofs(page_index),leaves,nonleaves);
  107. if (e!=-1) {
  108. if (page_index!=e+1) {
  109. tot += (e-s+1);
  110. if (verbose)
  111. printf(" 0x%" I64F "x-0x%" I64F "x = %" I64F "d\n",pagetoofs(s),pagetoofs(e+1)-1,pagetoofs(e-s+1));
  112. s = page_index;
  113. }
  114. }
  115. else
  116. s = page_index;
  117. e = page_index;
  118. }
  119. }
  120. if (e!=-1) {
  121. if (verbose)
  122. printf(" 0x%" I64F "x-0x%" I64F "x = %" I64F "d\n",pagetoofs(s),pagetoofs(e+1)-1,pagetoofs(e-s+1));
  123. tot += (e-s+1);
  124. }
  125. if (onlykey)
  126. printf(" Cached %" I64F "d of %" I64F "d = %0.2f% NonLeaves: %u, Leaves: %u\n",pagetoofs(tot),pagetoofs(fs),(double)tot*100.0/(double)fs,nonleaves,leaves);
  127. else
  128. printf(" Cached %" I64F "d of %" I64F "d = %0.2f%\n",pagetoofs(tot),pagetoofs(fs),(double)tot*100.0/(double)fs);
  129. free(mincore_vec);
  130. munmap(file_mmap, file_stat.st_size);
  131. close(fd);
  132. globtot += tot;
  133. globfs += fs;
  134. totlf += leaves;
  135. totnl += nonleaves;
  136. }
  137. void printPidCachedFiles(int pid,bool verbose,bool onlykey)
  138. {
  139. char path[128];
  140. char tmp[16];
  141. strcpy(path,"/proc/");
  142. strcat(path,itoa(pid,tmp,10));
  143. strcat(path,"/fd/");
  144. DIR * handle = ::opendir(path);
  145. if (!handle) {
  146. printf("ERROR: opendir %s failed %d\n",path,errno);
  147. return;
  148. }
  149. unsigned leaves = 0;
  150. unsigned nonleaves = 0;
  151. unsigned tot = 0;
  152. unsigned fs = 0;
  153. size_t pl = strlen(path);
  154. while (1) {
  155. struct dirent *entry = readdir(handle); // don't need _r here
  156. if (!entry)
  157. break;
  158. if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
  159. continue;
  160. strcat(path,entry->d_name);
  161. char link[258];
  162. size_t ll = readlink(path,link,sizeof(link));
  163. if (ll==(size_t)-1) {
  164. printf("ERROR readlink failed on %s with %d\n",path,errno);
  165. break;
  166. }
  167. link[ll] = 0;
  168. path[pl] = 0;
  169. printFileCache(link,tot,fs,verbose,onlykey,leaves,nonleaves);
  170. }
  171. closedir(handle);
  172. if (onlykey)
  173. printf("Total cached %" I64F "d of %" I64F "d = %0.2f% NonLeaves: %u, Leaves: %u\n",pagetoofs(tot),pagetoofs(fs),(double)tot*100.0/(double)fs,nonleaves,leaves);
  174. else
  175. printf("Total cached %" I64F "d of %" I64F "d = %0.2f%\n",pagetoofs(tot),pagetoofs(fs),(double)tot*100.0/(double)fs);
  176. }
  177. int main(int argc, const char *argv[])
  178. {
  179. offset_t nodeAddress = 0;
  180. if (argc < 2)
  181. {
  182. printf("Usage: fcached [ -v | -k ] <pid>\n");
  183. exit(2);
  184. }
  185. int arg=1;
  186. bool verbose = false;
  187. bool onlykey = false;
  188. if ((arg+1<argc)&&(stricmp(argv[arg],"-v")==0)) {
  189. verbose = true;
  190. arg++;
  191. }
  192. else if ((arg+1<argc)&&(stricmp(argv[arg],"-k")==0)) {
  193. onlykey = true;
  194. arg++;
  195. }
  196. printPidCachedFiles(atoi(argv[arg]),verbose,onlykey);
  197. return 0;
  198. }