gnunet-service-testbed_cpustatus.c 22 KB

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