gnunet-service-testbed_cpustatus.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2008--2013 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file testbed/gnunet-service-testbed_cpustatus.c
  19. * @brief calls to determine current CPU load
  20. * @author Tzvetan Horozov
  21. * @author Christian Grothoff
  22. * @author Igor Wronsky
  23. * @author Alex Harper (OS X portion)
  24. * @author Sree Harsha Totakura
  25. */
  26. #include "platform.h"
  27. #include "gnunet_util_lib.h"
  28. #include "gnunet-service-testbed_meminfo.h"
  29. #if SOLARIS
  30. #if HAVE_KSTAT_H
  31. #include <kstat.h>
  32. #endif
  33. #if HAVE_SYS_SYSINFO_H
  34. #include <sys/sysinfo.h>
  35. #endif
  36. #if HAVE_KVM_H
  37. #include <kvm.h>
  38. #endif
  39. #endif
  40. #if SOMEBSD
  41. #if HAVE_KVM_H
  42. #include <kvm.h>
  43. #endif
  44. #endif
  45. #ifdef OSX
  46. #include <mach/mach.h>
  47. static processor_cpu_load_info_t prev_cpu_load;
  48. #endif
  49. #ifdef WINDOWS
  50. #include <winternl.h>
  51. #endif
  52. #define DEBUG_STATUSCALLS GNUNET_NO
  53. #ifdef LINUX
  54. static FILE *proc_stat;
  55. #endif
  56. /**
  57. * Current CPU load, as percentage of CPU cycles not idle or
  58. * blocked on IO.
  59. */
  60. static int currentCPULoad;
  61. static double agedCPULoad = -1;
  62. /**
  63. * Current IO load, as percentage of CPU cycles blocked on IO.
  64. */
  65. static int currentIOLoad;
  66. static double agedIOLoad = -1;
  67. /**
  68. * hanlde to the file to write the load statistics to
  69. */
  70. struct GNUNET_BIO_WriteHandle *bw;
  71. GNUNET_SCHEDULER_TaskIdentifier sample_load_task_id;
  72. #ifdef OSX
  73. static int
  74. initMachCpuStats ()
  75. {
  76. unsigned int cpu_count;
  77. processor_cpu_load_info_t cpu_load;
  78. mach_msg_type_number_t cpu_msg_count;
  79. kern_return_t kret;
  80. int i, j;
  81. kret = host_processor_info (mach_host_self (),
  82. PROCESSOR_CPU_LOAD_INFO,
  83. &cpu_count,
  84. (processor_info_array_t *) & cpu_load,
  85. &cpu_msg_count);
  86. if (kret != KERN_SUCCESS)
  87. {
  88. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
  89. return GNUNET_SYSERR;
  90. }
  91. prev_cpu_load = GNUNET_malloc (cpu_count * sizeof (*prev_cpu_load));
  92. for (i = 0; i < cpu_count; i++)
  93. {
  94. for (j = 0; j < CPU_STATE_MAX; j++)
  95. {
  96. prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
  97. }
  98. }
  99. vm_deallocate (mach_task_self (),
  100. (vm_address_t) cpu_load,
  101. (vm_size_t) (cpu_msg_count * sizeof (*cpu_load)));
  102. return GNUNET_OK;
  103. }
  104. #endif
  105. /**
  106. * Update the currentCPU and currentIO load (and on Linux, memory) values.
  107. *
  108. * Before its first invocation the method initStatusCalls() must be called.
  109. * If there is an error the method returns -1.
  110. */
  111. static int
  112. updateUsage ()
  113. {
  114. currentIOLoad = -1;
  115. currentCPULoad = -1;
  116. #ifdef LINUX
  117. /* under linux, first try %idle/usage using /proc/stat;
  118. if that does not work, disable /proc/stat for the future
  119. by closing the file and use the next-best method. */
  120. if (proc_stat != NULL)
  121. {
  122. static unsigned long long last_cpu_results[5] = { 0, 0, 0, 0, 0 };
  123. static int have_last_cpu = GNUNET_NO;
  124. int ret;
  125. char line[256];
  126. unsigned long long user_read, system_read, nice_read, idle_read,
  127. iowait_read;
  128. unsigned long long user, system, nice, idle, iowait;
  129. unsigned long long usage_time = 0, total_time = 1;
  130. /* Get the first line with the data */
  131. rewind (proc_stat);
  132. fflush (proc_stat);
  133. if (NULL == fgets (line, 256, proc_stat))
  134. {
  135. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  136. "fgets", "/proc/stat");
  137. proc_stat = NULL; /* don't try again */
  138. }
  139. else
  140. {
  141. iowait_read = 0;
  142. ret = sscanf (line, "%*s %llu %llu %llu %llu %llu",
  143. &user_read,
  144. &system_read, &nice_read, &idle_read, &iowait_read);
  145. if (ret < 4)
  146. {
  147. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  148. "fgets-sscanf", "/proc/stat");
  149. fclose (proc_stat);
  150. proc_stat = NULL; /* don't try again */
  151. have_last_cpu = GNUNET_NO;
  152. }
  153. else
  154. {
  155. /* Store the current usage */
  156. user = user_read - last_cpu_results[0];
  157. system = system_read - last_cpu_results[1];
  158. nice = nice_read - last_cpu_results[2];
  159. idle = idle_read - last_cpu_results[3];
  160. iowait = iowait_read - last_cpu_results[4];
  161. /* Calculate the % usage */
  162. usage_time = user + system + nice;
  163. total_time = usage_time + idle + iowait;
  164. if ((total_time > 0) && (have_last_cpu == GNUNET_YES))
  165. {
  166. currentCPULoad = (int) (100L * usage_time / total_time);
  167. if (ret > 4)
  168. currentIOLoad = (int) (100L * iowait / total_time);
  169. else
  170. currentIOLoad = -1; /* 2.4 kernel */
  171. }
  172. /* Store the values for the next calculation */
  173. last_cpu_results[0] = user_read;
  174. last_cpu_results[1] = system_read;
  175. last_cpu_results[2] = nice_read;
  176. last_cpu_results[3] = idle_read;
  177. last_cpu_results[4] = iowait_read;
  178. have_last_cpu = GNUNET_YES;
  179. return GNUNET_OK;
  180. }
  181. }
  182. }
  183. #endif
  184. #ifdef OSX
  185. {
  186. unsigned int cpu_count;
  187. processor_cpu_load_info_t cpu_load;
  188. mach_msg_type_number_t cpu_msg_count;
  189. unsigned long long t_sys, t_user, t_nice, t_idle, t_total;
  190. unsigned long long t_idle_all, t_total_all;
  191. kern_return_t kret;
  192. int i, j;
  193. t_idle_all = t_total_all = 0;
  194. kret = host_processor_info (mach_host_self (), PROCESSOR_CPU_LOAD_INFO,
  195. &cpu_count,
  196. (processor_info_array_t *) & cpu_load,
  197. &cpu_msg_count);
  198. if (kret == KERN_SUCCESS)
  199. {
  200. for (i = 0; i < cpu_count; i++)
  201. {
  202. if (cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] >=
  203. prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM])
  204. {
  205. t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] -
  206. prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM];
  207. }
  208. else
  209. {
  210. t_sys = cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] +
  211. (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_SYSTEM] +
  212. 1);
  213. }
  214. if (cpu_load[i].cpu_ticks[CPU_STATE_USER] >=
  215. prev_cpu_load[i].cpu_ticks[CPU_STATE_USER])
  216. {
  217. t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER] -
  218. prev_cpu_load[i].cpu_ticks[CPU_STATE_USER];
  219. }
  220. else
  221. {
  222. t_user = cpu_load[i].cpu_ticks[CPU_STATE_USER] +
  223. (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_USER] +
  224. 1);
  225. }
  226. if (cpu_load[i].cpu_ticks[CPU_STATE_NICE] >=
  227. prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE])
  228. {
  229. t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE] -
  230. prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE];
  231. }
  232. else
  233. {
  234. t_nice = cpu_load[i].cpu_ticks[CPU_STATE_NICE] +
  235. (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_NICE] +
  236. 1);
  237. }
  238. if (cpu_load[i].cpu_ticks[CPU_STATE_IDLE] >=
  239. prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE])
  240. {
  241. t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE] -
  242. prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE];
  243. }
  244. else
  245. {
  246. t_idle = cpu_load[i].cpu_ticks[CPU_STATE_IDLE] +
  247. (ULONG_MAX - prev_cpu_load[i].cpu_ticks[CPU_STATE_IDLE] +
  248. 1);
  249. }
  250. t_total = t_sys + t_user + t_nice + t_idle;
  251. t_idle_all += t_idle;
  252. t_total_all += t_total;
  253. }
  254. for (i = 0; i < cpu_count; i++)
  255. {
  256. for (j = 0; j < CPU_STATE_MAX; j++)
  257. {
  258. prev_cpu_load[i].cpu_ticks[j] = cpu_load[i].cpu_ticks[j];
  259. }
  260. }
  261. if (t_total_all > 0)
  262. currentCPULoad = 100 - (100 * t_idle_all) / t_total_all;
  263. else
  264. currentCPULoad = -1;
  265. vm_deallocate (mach_task_self (),
  266. (vm_address_t) cpu_load,
  267. (vm_size_t) (cpu_msg_count * sizeof (*cpu_load)));
  268. currentIOLoad = -1; /* FIXME-OSX! */
  269. return GNUNET_OK;
  270. }
  271. else
  272. {
  273. GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "host_processor_info failed.");
  274. return GNUNET_SYSERR;
  275. }
  276. }
  277. #endif
  278. /* try kstat (Solaris only) */
  279. #if SOLARIS && HAVE_KSTAT_H && HAVE_SYS_SYSINFO_H
  280. {
  281. static long long last_idlecount;
  282. static long long last_totalcount;
  283. static int kstat_once; /* if open fails, don't keep
  284. trying */
  285. kstat_ctl_t *kc;
  286. kstat_t *khelper;
  287. long long idlecount;
  288. long long totalcount;
  289. long long deltaidle;
  290. long long deltatotal;
  291. if (kstat_once == 1)
  292. goto ABORT_KSTAT;
  293. kc = kstat_open ();
  294. if (kc == NULL)
  295. {
  296. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
  297. goto ABORT_KSTAT;
  298. }
  299. idlecount = 0;
  300. totalcount = 0;
  301. for (khelper = kc->kc_chain; khelper != NULL; khelper = khelper->ks_next)
  302. {
  303. cpu_stat_t stats;
  304. if (0 != strncmp (khelper->ks_name, "cpu_stat", strlen ("cpu_stat")))
  305. continue;
  306. if (khelper->ks_data_size > sizeof (cpu_stat_t))
  307. continue; /* better save then sorry! */
  308. if (-1 != kstat_read (kc, khelper, &stats))
  309. {
  310. idlecount += stats.cpu_sysinfo.cpu[CPU_IDLE];
  311. totalcount
  312. += stats.cpu_sysinfo.cpu[CPU_IDLE] +
  313. stats.cpu_sysinfo.cpu[CPU_USER] +
  314. stats.cpu_sysinfo.cpu[CPU_KERNEL] +
  315. stats.cpu_sysinfo.cpu[CPU_WAIT];
  316. }
  317. }
  318. if (0 != kstat_close (kc))
  319. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kstat_close");
  320. if ((idlecount == 0) && (totalcount == 0))
  321. goto ABORT_KSTAT; /* no stats found => abort */
  322. deltaidle = idlecount - last_idlecount;
  323. deltatotal = totalcount - last_totalcount;
  324. if ((deltatotal > 0) && (last_totalcount > 0))
  325. {
  326. currentCPULoad = (unsigned int) (100.0 * deltaidle / deltatotal);
  327. if (currentCPULoad > 100)
  328. currentCPULoad = 100; /* odd */
  329. if (currentCPULoad < 0)
  330. currentCPULoad = 0; /* odd */
  331. currentCPULoad = 100 - currentCPULoad; /* computed idle-load before! */
  332. }
  333. else
  334. currentCPULoad = -1;
  335. currentIOLoad = -1; /* FIXME-SOLARIS! */
  336. last_idlecount = idlecount;
  337. last_totalcount = totalcount;
  338. return GNUNET_OK;
  339. ABORT_KSTAT:
  340. kstat_once = 1; /* failed, don't try again */
  341. return GNUNET_SYSERR;
  342. }
  343. #endif
  344. /* insert methods better than getloadavg for
  345. other platforms HERE! */
  346. /* ok, maybe we have getloadavg on this platform */
  347. #if HAVE_GETLOADAVG
  348. {
  349. static int warnOnce = 0;
  350. double loadavg;
  351. if (1 != getloadavg (&loadavg, 1))
  352. {
  353. /* only warn once, if there is a problem with
  354. getloadavg, we're going to hit it frequently... */
  355. if (warnOnce == 0)
  356. {
  357. warnOnce = 1;
  358. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "getloadavg");
  359. }
  360. return GNUNET_SYSERR;
  361. }
  362. else
  363. {
  364. /* success with getloadavg */
  365. currentCPULoad = (int) (100 * loadavg);
  366. currentIOLoad = -1; /* FIXME */
  367. return GNUNET_OK;
  368. }
  369. }
  370. #endif
  371. #if MINGW
  372. /* Win NT? */
  373. if (GNNtQuerySystemInformation)
  374. {
  375. static double dLastKernel;
  376. static double dLastIdle;
  377. static double dLastUser;
  378. double dKernel;
  379. double dIdle;
  380. double dUser;
  381. double dDiffKernel;
  382. double dDiffIdle;
  383. double dDiffUser;
  384. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION theInfo;
  385. if (GNNtQuerySystemInformation (SystemProcessorPerformanceInformation,
  386. &theInfo,
  387. sizeof (theInfo), NULL) == NO_ERROR)
  388. {
  389. /* PORT-ME MINGW: Multi-processor? */
  390. dKernel = Li2Double (theInfo.KernelTime);
  391. dIdle = Li2Double (theInfo.IdleTime);
  392. dUser = Li2Double (theInfo.UserTime);
  393. dDiffKernel = dKernel - dLastKernel;
  394. dDiffIdle = dIdle - dLastIdle;
  395. dDiffUser = dUser - dLastUser;
  396. if (((dDiffKernel + dDiffUser) > 0) &&
  397. (dLastIdle + dLastKernel + dLastUser > 0))
  398. currentCPULoad =
  399. 100.0 - (dDiffIdle / (dDiffKernel + dDiffUser)) * 100.0;
  400. else
  401. currentCPULoad = -1; /* don't know (yet) */
  402. dLastKernel = dKernel;
  403. dLastIdle = dIdle;
  404. dLastUser = dUser;
  405. currentIOLoad = -1; /* FIXME-MINGW */
  406. return GNUNET_OK;
  407. }
  408. else
  409. {
  410. /* only warn once, if there is a problem with
  411. NtQuery..., we're going to hit it frequently... */
  412. static int once;
  413. if (once == 0)
  414. {
  415. once = 1;
  416. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  417. "Cannot query the CPU usage (Windows NT).\n");
  418. }
  419. return GNUNET_SYSERR;
  420. }
  421. }
  422. else
  423. { /* Win 9x */
  424. HKEY hKey;
  425. DWORD dwDataSize, dwType, dwDummy;
  426. /* Start query */
  427. if (RegOpenKeyEx (HKEY_DYN_DATA,
  428. "PerfStats\\StartSrv",
  429. 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS)
  430. {
  431. /* only warn once */
  432. static int once = 0;
  433. if (once == 0)
  434. {
  435. once = 1;
  436. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  437. "Cannot query the CPU usage (Win 9x)\n");
  438. }
  439. }
  440. RegOpenKeyEx (HKEY_DYN_DATA,
  441. "PerfStats\\StartStat", 0, KEY_ALL_ACCESS, &hKey);
  442. dwDataSize = sizeof (dwDummy);
  443. RegQueryValueEx (hKey,
  444. "KERNEL\\CPUUsage",
  445. NULL, &dwType, (LPBYTE) & dwDummy, &dwDataSize);
  446. RegCloseKey (hKey);
  447. /* Get CPU usage */
  448. RegOpenKeyEx (HKEY_DYN_DATA,
  449. "PerfStats\\StatData", 0, KEY_ALL_ACCESS, &hKey);
  450. dwDataSize = sizeof (currentCPULoad);
  451. RegQueryValueEx (hKey,
  452. "KERNEL\\CPUUsage",
  453. NULL, &dwType, (LPBYTE) & currentCPULoad, &dwDataSize);
  454. RegCloseKey (hKey);
  455. currentIOLoad = -1; /* FIXME-MINGW! */
  456. /* Stop query */
  457. RegOpenKeyEx (HKEY_DYN_DATA,
  458. "PerfStats\\StopStat", 0, KEY_ALL_ACCESS, &hKey);
  459. RegOpenKeyEx (HKEY_DYN_DATA,
  460. "PerfStats\\StopSrv", 0, KEY_ALL_ACCESS, &hKey);
  461. dwDataSize = sizeof (dwDummy);
  462. RegQueryValueEx (hKey,
  463. "KERNEL\\CPUUsage",
  464. NULL, &dwType, (LPBYTE) & dwDummy, &dwDataSize);
  465. RegCloseKey (hKey);
  466. return GNUNET_OK;
  467. }
  468. #endif
  469. /* loadaverage not defined and no platform
  470. specific alternative defined
  471. => default: error
  472. */
  473. return GNUNET_SYSERR;
  474. }
  475. /**
  476. * Update load values (if enough time has expired),
  477. * including computation of averages. Code assumes
  478. * that lock has already been obtained.
  479. */
  480. static void
  481. updateAgedLoad ()
  482. {
  483. static struct GNUNET_TIME_Absolute lastCall;
  484. struct GNUNET_TIME_Relative age;
  485. age = GNUNET_TIME_absolute_get_duration (lastCall);
  486. if ( (agedCPULoad == -1)
  487. || (age.rel_value_us > 500000) )
  488. {
  489. /* use smoothing, but do NOT update lastRet at frequencies higher
  490. than 500ms; this makes the smoothing (mostly) independent from
  491. the frequency at which getCPULoad is called (and we don't spend
  492. more time measuring CPU than actually computing something). */
  493. lastCall = GNUNET_TIME_absolute_get ();
  494. updateUsage ();
  495. if (currentCPULoad == -1)
  496. {
  497. agedCPULoad = -1;
  498. }
  499. else
  500. {
  501. if (agedCPULoad == -1)
  502. {
  503. agedCPULoad = currentCPULoad;
  504. }
  505. else
  506. {
  507. /* for CPU, we don't do the 'fast increase' since CPU is much
  508. more jitterish to begin with */
  509. agedCPULoad = (agedCPULoad * 31 + currentCPULoad) / 32;
  510. }
  511. }
  512. if (currentIOLoad == -1)
  513. {
  514. agedIOLoad = -1;
  515. }
  516. else
  517. {
  518. if (agedIOLoad == -1)
  519. {
  520. agedIOLoad = currentIOLoad;
  521. }
  522. else
  523. {
  524. /* for IO, we don't do the 'fast increase' since IO is much
  525. more jitterish to begin with */
  526. agedIOLoad = (agedIOLoad * 31 + currentIOLoad) / 32;
  527. }
  528. }
  529. }
  530. }
  531. /**
  532. * Get the load of the CPU relative to what is allowed.
  533. * @return the CPU load as a percentage of allowed
  534. * (100 is equivalent to full load)
  535. */
  536. static int
  537. cpu_get_load ()
  538. {
  539. updateAgedLoad ();
  540. return (int) agedCPULoad;
  541. }
  542. /**
  543. * Get the load of the CPU relative to what is allowed.
  544. * @return the CPU load as a percentage of allowed
  545. * (100 is equivalent to full load)
  546. */
  547. static int
  548. disk_get_load ()
  549. {
  550. updateAgedLoad ();
  551. return (int) agedIOLoad;
  552. }
  553. /**
  554. * Get the percentage of memory used
  555. *
  556. * @return the percentage of memory used
  557. */
  558. static unsigned int
  559. mem_get_usage ()
  560. {
  561. double percentage;
  562. meminfo ();
  563. percentage = ( ((double) kb_main_used) / ((double) kb_main_total) * 100.0 );
  564. return (unsigned int) percentage;
  565. }
  566. #ifdef LINUX
  567. #include <dirent.h>
  568. /**
  569. * Returns the number of processes
  570. *
  571. * @return the number of processes
  572. */
  573. static unsigned int
  574. get_nproc ()
  575. {
  576. DIR *dir;
  577. struct dirent *ent;
  578. unsigned int nproc;
  579. dir = opendir ("/proc");
  580. if (NULL == dir)
  581. return 0;
  582. nproc = 0;
  583. while (NULL != (ent = readdir (dir)))
  584. {
  585. if((*ent->d_name > '0') && (*ent->d_name <= '9'))
  586. nproc++;
  587. }
  588. closedir (dir);
  589. return nproc;
  590. }
  591. #endif
  592. static void
  593. sample_load_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  594. {
  595. struct GNUNET_TIME_Absolute now;
  596. char *str;
  597. int nbs;
  598. int ld_cpu;
  599. int ld_disk;
  600. unsigned int mem_usage;
  601. unsigned int nproc;
  602. sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
  603. if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
  604. return;
  605. ld_cpu = cpu_get_load ();
  606. ld_disk = disk_get_load ();
  607. if ( (-1 == ld_cpu) || (-1 == ld_disk) )
  608. goto reschedule;
  609. mem_usage = mem_get_usage ();
  610. #ifdef LINUX
  611. nproc = get_nproc ();
  612. #else
  613. nproc = 0;
  614. #endif
  615. now = GNUNET_TIME_absolute_get ();
  616. nbs = GNUNET_asprintf (&str, "%llu %d %d %u %u\n", now.abs_value_us / 1000LL / 1000LL,
  617. ld_cpu, ld_disk, mem_usage, nproc);
  618. if (0 < nbs)
  619. {
  620. GNUNET_BIO_write (bw, str, nbs);
  621. }
  622. else
  623. GNUNET_break (0);
  624. GNUNET_free (str);
  625. reschedule:
  626. sample_load_task_id =
  627. GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
  628. &sample_load_task, NULL);
  629. }
  630. /**
  631. * Initialize logging CPU and IO statisticfs. Checks the configuration for
  632. * "STATS_DIR" and logs to a file in that directory. The file is name is
  633. * generated from the hostname and the process's PID.
  634. */
  635. void
  636. GST_stats_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
  637. {
  638. char *hostname;
  639. char *stats_dir;
  640. char *fn;
  641. size_t len;
  642. #if MINGW
  643. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  644. "Load statistics logging now available for windows\n");
  645. return; /* No logging on windows for now :( */
  646. #endif
  647. if (GNUNET_OK !=
  648. GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
  649. "STATS_DIR", &stats_dir))
  650. return;
  651. len = GNUNET_OS_get_hostname_max_length ();
  652. hostname = GNUNET_malloc (len);
  653. if (0 != gethostname (hostname, len))
  654. {
  655. GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "gethostname");
  656. GNUNET_free (stats_dir);
  657. GNUNET_free (hostname);
  658. return;
  659. }
  660. fn = NULL;
  661. (void) GNUNET_asprintf (&fn, "%s/%.*s-%jd.dat", stats_dir, len,
  662. hostname, (intmax_t) getpid());
  663. GNUNET_free (stats_dir);
  664. GNUNET_free (hostname);
  665. if (NULL == (bw = GNUNET_BIO_write_open (fn)))
  666. {
  667. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  668. _("Cannot open %s for writing load statistics. "
  669. "Not logging load statistics\n"), fn);
  670. GNUNET_free (fn);
  671. return;
  672. }
  673. GNUNET_free (fn);
  674. sample_load_task_id = GNUNET_SCHEDULER_add_now (&sample_load_task, NULL);
  675. #ifdef LINUX
  676. proc_stat = fopen ("/proc/stat", "r");
  677. if (NULL == proc_stat)
  678. GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
  679. "fopen", "/proc/stat");
  680. #elif OSX
  681. initMachCpuStats ();
  682. #endif
  683. updateUsage (); /* initialize */
  684. }
  685. /**
  686. * Shutdown the status calls module.
  687. */
  688. void
  689. GST_stats_destroy ()
  690. {
  691. #if MINGW
  692. return;
  693. #endif
  694. if (NULL == bw)
  695. return;
  696. #ifdef LINUX
  697. if (proc_stat != NULL)
  698. {
  699. fclose (proc_stat);
  700. proc_stat = NULL;
  701. }
  702. #elif OSX
  703. GNUNET_free_non_null (prev_cpu_load);
  704. #endif
  705. if (GNUNET_SCHEDULER_NO_TASK != sample_load_task_id)
  706. {
  707. GNUNET_SCHEDULER_cancel (sample_load_task_id);
  708. sample_load_task_id = GNUNET_SCHEDULER_NO_TASK;
  709. }
  710. GNUNET_break (GNUNET_OK == GNUNET_BIO_write_close (bw));
  711. bw = NULL;
  712. }
  713. /* end of cpustatus.c */