RDK Documentation (Open Sourced RDK Components)
cpuproc_analyzer.cpp
1 /* If not stated otherwise in this file or this component's Licenses.txt file the
2  * following copyright and licenses apply:
3  *
4  * Copyright 2018 RDK Management
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17 */
18 
19 #include <sys/socket.h>
20 #include <linux/netlink.h>
21 #include <linux/connector.h>
22 #include <linux/cn_proc.h>
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <sys/time.h>
29 #include <signal.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <string>
33 #include <string.h>
34 #include <map>
35 #include <sstream>
36 #include <stdarg.h>
37 
38 #ifdef PROCANALYZER_BROADBAND
39 #include <telemetry_busmessage_sender.h>
40 #include <json-c/json.h>
41 #endif
42 
43 #ifndef PROCANALYZER_EXTENDER
44 #include "rdk_debug.h"
45 #endif
46 #include <bits/stdc++.h>
47 using namespace std;
48 
49 #ifndef PROCANALYZER_EXTENDER
50 extern "C" {
51  // C Function call
52 #include <cimplog/cimplog.h>
53 #define LOGGING_MODULE "CPUPROCANALYZER"
54 const char *rdk_logger_module_fetch(void);
55 }
56 #endif
57 
58 /**
59  * @defgroup CPU_PROC_ANALYZER CPU Proc Analyzer
60  *
61  * - RDK PROC ANALYZER is a tool that enables different teams like :
62  * development, triage and testing to analyze the CPU and memory utilization of the processes that run on top of RDK framework.
63  * - It runs periodically to collect cpu utilisation,load average and memory usage.
64  * - It helps us in detecting the memory leaks, cpu and memory performance regressions.
65  * - This tool is implemented as a service and is also highly configurable
66  *
67  * Flow diagram of CPU Proc Analyzer -
68  * @image html CPUproc_analyzer_Flowchart_main.png
69  * @image html CPUproc_analyzer_Flowchart_1.png
70  *
71  * @defgroup CPU_PROC_ANALYZER_API CPU Proc Public APIs
72  * @ingroup CPU_PROC_ANALYZER
73  *
74  * @defgroup CPU_PROC_ANALYZER_TYPES CPU Proc Data Types
75  * @ingroup CPU_PROC_ANALYZER
76  */
77 
78 /**
79  * @addtogroup CPU_PROC_ANALYZER_TYPES
80  * @{
81  */
82 
83 #define LINE_LIMIT 256 //!< FILE LINE LIMIT
84 #define NAME_LIMIT 20 //!< FILE NAME LIMIT
85 #define SLEEP_SECS 60 //!< Sleep Interval for the data collection
86 #define TIME_TO_RUN_SECS 0 //!< 0 means, tool should run until it is killed manually
87 #define BUFF_SIZE_64 64
88 #define BUFF_SIZE_16 16
89 #define DEFAULT_MEM_THRESHOLD 1536 //Max filesize limit
90 #define MONITOR_ALL_PROC_DEF 0 //Default Monitor all process flag
91 #define DEFAULT_DYNAMIC 1 //Default for Dynamic
92 #define ITERATION_THRESHOLD 25 //Max number of runs
93 #define TELEMETRY_ONLY_DEF 0 // Only telemetry reporting default flag
94 
95 #define CPU_MASK 0x10
96 #define MEMORY_MASK 0x08
97 #define FDCOUNT_MASK 0x04
98 #define THREADCOUNT_MASK 0x02
99 #define LOADAVG_MASK 0x02
100 #define CLICOUNT_MASK 0x01
101 
102 #define SYS_DEF_MASK 0x1F
103 #define PROC_DEF_MASK 0x1E
104 
105 typedef unsigned int uint;
106 
107 #ifdef PROCANALYZER_BROADBAND
108 uint PROC_MASK = 0x00;
109 uint SYS_MASK = 0x00;
110 #else
111 uint PROC_MASK = 0x1E;
112 uint SYS_MASK = 0x1F;
113 #endif
114 
115 #define MAX(x,y) ((x>y)?x:y)
116 
117 #define PROC_EVENT_NONE 0x00000000
118 #define PROC_EVENT_FORK 0x00000001
119 #define PROC_EVENT_EXEC 0x00000002
120 #ifdef PROCANALYZER_EXTENDER
121 #define RDK_LOG_ERROR 0
122 #define RDK_LOG_DEBUG 1
123 #define RDK_LOG_INFO 2
124 #define RDK_LOG_TRACE1 3
125 #define RDK_LOG get_proclog
126 #define EXTENDER_VENDOR_NAME_STR "vendor_name"
127 #define EXTENDER_MODEL_NAME_STR "model"
128 #endif
129 pthread_mutex_t mtx;
130 /**
131  * @struct stPrevData
132  *
133  * @brief Holds status of previous data such as Total Major Faults Raised,Total CPU Used Time,User Used CPU Time,System Used CPU Time.
134  */
136 {
137  unsigned int prevTotalMajFaultsRaised;
138  unsigned long prevTotalUsedCPUTime;
139  unsigned long prevUserUsedCPUTime;
140  unsigned long prevSystemUsedCPUTime;
141  double prevTotalCPUTime_usec;
142  bool status;
143 };
144 
145 /**
146  * @struct stCPUInfo
147  *
148  * @brief Holds status of CPU information such as Total Time and Idle Time of CPU.
149  */
150 struct stCPUInfo
151 {
152  unsigned long long total;
153  unsigned long long idle;
154 } prevCPUInfo;
155 
156 typedef struct EnvVarNode
157 {
158  char* name;
159  char* value;
160  struct EnvVarNode *next;
161 } EnvVarNode;
162 
163 
164 map<unsigned int, struct stPrevData> prevData;
165 
166 FILE* fp_selectedps = NULL;
167 FILE* fp_stat = NULL;
168 FILE* fp_dataOut = NULL;
169 
170 #if defined PROCANALYZER_BROADBAND
171  #define CONFIG_PATH "/nvram"
172  #define LOG_PATH "/tmp"
173 #elif defined PROCANALYZER_EXTENDER
174  #define CONFIG_PATH "/usr/opensync/scripts"
175  #define LOG_PATH "/tmp"
176 #else
177  #define CONFIG_PATH "/opt"
178  #define LOG_PATH "/opt/logs"
179 #endif
180 
181 string outputDir = LOG_PATH"/cpuprocanalyzer/";
182 string outputDynamicDir = LOG_PATH"/cpuprocanalyzer/dynamic/";
183 
184 long totalTimeElapsed_sec = 0;
185 char strTime[80];
186 list<string> exclude_process_list;
187 list<string> :: iterator it;
188 #ifdef PROCANALYZER_EXTENDER
189 // Get the Log level
190 char* GetCurTimeStamp();
191 void get_proclog(int log_level,const char * log_module ,const char *format, ...)
192 {
193  printf("%s\t",GetCurTimeStamp());
194  if(log_level==0){
195  printf("<ERROR>\t");
196  }
197  else if(log_level==1){
198  printf("<DEBUG>\t");
199  }
200  else if(log_level==2){
201  printf("<INFO>\t");
202  }
203  else if(log_level==3){
204  printf("<TRACE1>\t");
205  }
206  va_list args;
207  printf("%s\t",log_module);
208  va_start(args, format);
209  vprintf(format, args);
210  printf("\n");
211  va_end(args);
212  return;
213 }
214 
215 int get_device_param(char* param,char* value)
216 {
217  char tmp_string[BUFF_SIZE_64] ="\0";
218  char buf1[BUFF_SIZE_64] ="\0";
219  sprintf(tmp_string," ovsh s AWLAN_Node %s -j | grep :",param);
220  FILE * fp = popen(tmp_string, "r");
221  if (fp == 0)
222  {
223  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", " popen failed.Failed to run the command.\n");
224  return -1;
225  }
226  fgets(buf1, BUFF_SIZE_64, fp);
227  sscanf(buf1," \"%[^'\"''']\": \"%[^'\"']\"",tmp_string,value);
228  pclose(fp);
229  return 1;
230 }
231 #endif
232 
233 char* removespaces(char *str);
234 int read_config_param(const char *paramname,const char *filename,char *res)
235 {
236  FILE *fp = fopen(filename,"r");
237  char tmp_string[128] = {0};
238  char* tmp;
239  char* pch;
240  if(fp)
241  {
242  memset(tmp_string,0,128);
243  while(fgets(tmp_string,128,fp)!= NULL)
244  {
245  if(strstr(tmp_string,paramname))
246  {
247  tmp=removespaces(tmp_string);
248  pch=strchr(tmp,'=');
249  pch=pch+1;
250  strncpy(res,pch,BUFF_SIZE_64);
251  return 1;
252  }
253  memset(tmp_string,0,128);
254  }
255  fclose(fp);
256  }
257  return 0;
258 }
259 
260 char* removespaces(char *str)
261 {
262  int i=0,j=0;
263  while(str[i] != NULL)
264  {
265  if (str[i] != ' ')
266  str[j++] = str[i];
267  i++;
268  }
269  str[j] = '\0';
270  return str;
271 }
272 /**
273  * @}
274  */
275 
276 /**
277  * @addtogroup CPU_PROC_ANALYZER_API
278  * @{
279  */
280 
281 /**
282  * @brief This function reads the Process Name from /proc/stat.
283  *
284  * @param[in] fp File Pointer
285  * @param[in] procName Process Name
286  */
287 void ReadProcessName(FILE* fp, char* procName)
288 {
289  char ch;
290  int i = 0;
291  while(!feof(fp) && fgetc(fp) != '(');
292  while(!feof(fp))
293  {
294  ch = fgetc(fp);
295  if(ch == ')' || ferror(fp) || feof(fp)) break;
296  //REPLACING CHARACTERS IN PROCESS NAME
297  if(ch == 0 || ch == ' ' || ch==':' || ch == '\\' || ch == '/' || ch == '[' || ch == ']' || ch == '{' || ch == '}' || ch == '(' || ch == ')')
298  ch = '-';
299  procName[i] = ch;
300 
301  ++i;
302  }
303  procName[i] = '\0';
304 }
305 
306 /**
307  * @brief This function reads the Process Command Line Output from /proc/cmdline and removes extra characters.
308  *
309  * @param[in] fp File Pointer
310  * @param[in] str String
311  */
312 void ReadSkippingRandomChar(FILE* fp, char* str)
313 {
314  char ch;
315  int i = 0;
316  while(!feof(fp))
317  {
318  ch = fgetc(fp);
319  if(ferror(fp) || feof(fp)) break;
320  if(ch == 0) ch = ' ';
321  str[i] = ch;
322  ++i;
323  }
324  str[i] = '\0';
325 }
326 
327 
328 /**
329  * @brief This function retrieves value of matching string from a file.
330  */
331 char* GetValuesFromFile (char *fname, char *searchStr, char *strValue, unsigned int strValueLen)
332 {
333  char buf1[BUFF_SIZE_64] = "\0";
334  char tmpStr[BUFF_SIZE_64] = "\0";
335  char srch[BUFF_SIZE_64] = "\0";
336 
337  FILE *fp = fopen (fname, "r" );
338 
339  if (!fp) {
340  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "fopen failed.Failed to read %s\n", searchStr);
341  return NULL;
342  }
343 
344  memset(buf1, 0, BUFF_SIZE_64);
345  memset(tmpStr, 0, BUFF_SIZE_64);
346 
347  while (fgets(buf1,BUFF_SIZE_64,fp)) {
348 
349  if (strstr(buf1, searchStr)) {
350  memset (srch, 0, sizeof(srch));
351  sprintf(srch, "%s%%s", searchStr);
352  sscanf (buf1, srch, tmpStr);
353  strncpy (strValue, tmpStr, strValueLen-1);
354 
355  if (strValue[strlen(strValue)] == '\n') {
356  strValue[strlen(strValue)] = '\0';
357  }
358  break;
359  }
360  }
361  fclose(fp);
362  return strValue;
363 }
364 
365 #if defined PROCANALYZER_BROADBAND
366 void ReadRFCJson()
367 {
368  string rfc_filename = outputDir + "rfc_list.txt";
369  static const char filename[] = "/tmp/rfc-current.json";
370 
371  if(access(filename, R_OK))
372  {
373  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "rfc-current.json is not accessible.\n");
374  return;
375  }
376 
377  FILE *fp1 = fopen(rfc_filename.c_str(),"a");
378  struct json_object *obj, *feature_obj, *feaCtrl_obj, *featArr_obj, *name_obj, *enable_obj;
379 
380  obj = json_object_from_file(filename);
381  feaCtrl_obj = json_object_object_get(obj, "featureControl");
382  feature_obj = json_object_object_get(feaCtrl_obj, "features");
383 
384  int arrlen = json_object_array_length(feature_obj);
385 
386  if(fp1)
387  {
388  for(int i=0; i<arrlen; i++)
389  {
390  featArr_obj = json_object_array_get_idx(feature_obj, i);
391  name_obj = json_object_object_get(featArr_obj, "name");
392  enable_obj = json_object_object_get(featArr_obj, "enable");
393  fprintf(fp1, "%s : %s\n", json_object_get_string(name_obj), json_object_get_string(enable_obj));
394  }
395  fclose(fp1);
396  }
397  else
398  {
399  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "Cannot open RFC file.\n");
400  }
401  json_object_put(obj);
402 }
403 #endif
404 
405 void GetNumOfClientsConnected(unsigned int *cliCount)
406 {
407  char buf[8] = {0};
408  FILE *fp = NULL;
409 
410  fp = popen("dmcli eRT getv Device.Hosts.HostNumberOfEntries | grep value | awk '{print $5}'", "r");
411  if(fp)
412  {
413  if(fgets(buf, 8, fp))
414  {
415  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "Number of Clients connected : %d\n", atoi(buf));
416  *cliCount = atoi(buf);
417  }
418  pclose(fp);
419  }
420  else
421  {
422  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "Popen failure\n");
423  }
424 }
425 
426 /**
427  * @brief This function retrieves device name and manufacturer name.
428  */
430 {
431  char mfgname[BUFF_SIZE_16] = "\0";
432  char devicename[BUFF_SIZE_16] = "\0";
433  char buildname[BUFF_SIZE_64] = "\0";
434  char name[100] = "\0";
435 
436  #if defined PROCANALYZER_BROADBAND
437  memset (mfgname, 0, BUFF_SIZE_16);
438  GetValuesFromFile ("/etc/device.properties", "MANUFACTURE=", mfgname, sizeof(mfgname));
439 
440  if (strncmp(mfgname,"UNKNOWN",strlen(mfgname))) {
441  GetValuesFromFile ("/etc/device.properties", "MFG_NAME=", mfgname, sizeof(mfgname));
442  }
443 
444  memset(devicename,0,BUFF_SIZE_16);
445  GetValuesFromFile ("/etc/device.properties", "BOX_TYPE=", devicename, sizeof(devicename));
446  #elif defined PROCANALYZER_EXTENDER
447  get_device_param(EXTENDER_VENDOR_NAME_STR,mfgname);
448  get_device_param(EXTENDER_MODEL_NAME_STR,devicename);
449  #else
450 
451  memset (mfgname, 0, BUFF_SIZE_16);
452  GetValuesFromFile ("/etc/device.properties", "MFG_NAME=", mfgname, sizeof(mfgname));
453 
454  memset(devicename,0,BUFF_SIZE_16);
455  GetValuesFromFile ("/etc/device.properties", "DEVICE_NAME=", devicename, sizeof(devicename));
456 
457  #endif
458 
459  memset (name, 0, sizeof(name));
460  snprintf (name, BUFF_SIZE_64, "%s%s", mfgname, devicename);
461 
462  memset(buildname, 0, sizeof(buildname));
463  GetValuesFromFile ("/version.txt", "imagename:", buildname, sizeof(buildname));
464 
465  if (!strcmp(buildname, "")) {
466  GetValuesFromFile ("/version.txt", "imagename=", buildname, sizeof(buildname));
467  }
468 
469 
470  FILE *fpout = fopen(LOG_PATH"/cpuprocanalyzer/deviceinfo.data", "w");
471 
472  if (!fpout) {
473  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "Could not open deviceInfo.data.\n");
474  }
475  else {
476  fprintf(fpout, "DEVICE_NAME:%s\nBUILD_NAME:%s\n ", name, buildname);
477  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "Device name %s and Build name %s written successfully.\n",name, buildname);
478  fclose (fpout);
479  }
480 }
481 
482 /**
483  * @}
484  */
485 
486 /**
487  * @addtogroup CPU_PROC_ANALYZER_TYPES
488  * @{
489  */
490 
491 /**
492  * @struct stProcData
493  *
494  * @brief Holds status of Process data such as :
495  * - PID of process, Process State, Parent PID, Process Group ID, Session ID of the Process.
496  * - The Kernel Flags word of the Process, Major Faults, Minor Faults, Nice value, Number of threads in the process.
497  * - Resident Set Size, Virtual memory size, Real-time scheduling priority, Scheduling Policy.
498  */
500 {
501  int d_pid;
502  char s_comm[1000], c_state;
503  int d_ppid, d_pgrp, d_session, d_tty_nr, d_tpgid;
504  unsigned u_flags;
505  unsigned long lu_minflt, lu_cminflt, lu_majflt, lu_cmajflt, lu_utime, lu_stime;
506  long ld_cutime, ld_cstime, ld_priority, ld_nice, ld_num_threads, ld_itrealvalue;
507  unsigned long long llu_starttime;
508  unsigned long lu_vsize;
509  long ld_rss;
510  unsigned long lu_rsslim, lu_startcode, lu_endcode, lu_startstack, lu_kstkesp, lu_kstkeip, lu_signal, lu_blocked, lu_sigignore, lu_sigcatch, lu_wchan, lu_nswap, lu_cnswap;
511  int d_exit_signal, d_processor;
512  unsigned int u_rt_priority, u_policy;
513  unsigned long long llu_delayacct_blkio_ticks;
514  unsigned long lu_guest_time;
515  long ld_cguest_time;
516 
517 /**
518  * @}
519  */
520 
521 /**
522  * @addtogroup CPU_PROC_ANALYZER_API
523  * @{
524  */
525 
526 /**
527  * @brief This function reads status of the Process and gives information like :
528  * - Parent PID, Parent Name, Number of threads in the Process
529  *
530  * @param[in] fp_procStat File Pointer
531  */
532  void ReadProcStat(FILE* fp_procStat)
533  {
534 
535  fscanf(fp_procStat, "%d", &d_pid);
536  ReadProcessName(fp_procStat, s_comm);
537  fscanf(fp_procStat, " %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld", &c_state, &d_ppid, &d_pgrp, &d_session, &d_tty_nr, &d_tpgid, &u_flags, &lu_minflt, &lu_cminflt, &lu_majflt, &lu_cmajflt, &lu_utime, &lu_stime, &ld_cutime, &ld_cstime, &ld_priority, &ld_nice, &ld_num_threads, &ld_itrealvalue, &llu_starttime, &lu_vsize, &ld_rss, &lu_rsslim, &lu_startcode, &lu_endcode, &lu_startstack, &lu_kstkesp, &lu_kstkeip, &lu_signal, &lu_blocked, &lu_sigignore, &lu_sigcatch, &lu_wchan, &lu_nswap, &lu_cnswap, &d_exit_signal, &d_processor, &u_rt_priority, &u_policy, &llu_delayacct_blkio_ticks, &lu_guest_time, &ld_cguest_time);
538 
539  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER","%s(%d): %d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", __func__, __LINE__, d_pid, s_comm, c_state, d_ppid, d_pgrp, d_session, d_tty_nr, d_tpgid, u_flags, lu_minflt, lu_cminflt, lu_majflt, lu_cmajflt, lu_utime, lu_stime, ld_cutime, ld_cstime, ld_priority, ld_nice, ld_num_threads, ld_itrealvalue, llu_starttime, lu_vsize, ld_rss, lu_rsslim, lu_startcode, lu_endcode, lu_startstack, lu_kstkesp, lu_kstkeip, lu_signal, lu_blocked, lu_sigignore, lu_sigcatch, lu_wchan, lu_nswap, lu_cnswap, d_exit_signal, d_processor, u_rt_priority, u_policy, llu_delayacct_blkio_ticks, lu_guest_time, ld_cguest_time);
540 
541  }
542 
543 /**
544  * @brief This function constructs a file name based on parameters such as - output Directory Name,PID value,s_comm data,PID value,s_comm data.
545  * For example : "/opt/logs/cpuprocanalyzer/<PID value>/s_comm/<PID value>/s_comm"
546  *
547  * @param[in] outProcFilename Output Process Filename
548  */
549  void OutFilename(char* outProcFilename,int is_dynamic)
550  {
551  if(is_dynamic == 1)
552  {
553  sprintf(outProcFilename, "%s%d_%s/%d_%s.data", outputDynamicDir.c_str(), d_pid, s_comm,d_pid,s_comm);
554  }
555  else
556  {
557  sprintf(outProcFilename, "%s%d_%s/%d_%s.data", outputDir.c_str(), d_pid, s_comm,d_pid, s_comm);
558  }
559  }
560 
561 /**
562  * @brief This function constructs a file name based on parameters such as - output Directory Name,PPID value,Parent process Name,PID value,s_comm data.
563  * For example : "/opt/logs/cpuprocanalyzer/<PPID value>/<Parent process name>/<PID value>/s_comm"
564  *
565  * @param[in] outProcFilename Output Process Filename
566  * @param[in] ppid Parent PID
567  * @param[in] pname Parent Name
568  */
569  void OutFilename(char* outProcFilename, int ppid, char* pname)
570  {
571  sprintf(outProcFilename, "%s%d_%s/threads/%d_%s.data", outputDir.c_str(), ppid, pname, d_pid, s_comm);
572  }
573 
574 /**
575  * @brief This function gives Total CPU used time.
576  *
577  * - Total CPU Used Time value is the sum of User Used CPU Time value and System Used CPU Time value
578  *
579  * @param[out] outTotalTime Output Total CPU Used Time value
580  */
581  void GetTotalUsedTime(unsigned long* outTotalTime)
582  {
583  *outTotalTime = lu_utime + lu_stime;// + (ld_cutime + ld_cstime);
584  }
585 
586 /**
587  * @brief This function gives User used CPU time.
588  *
589  * - User time is the amount of time the CPU was busy executing code in user space.
590  *
591  * @param[out] outUserTime Output User used CPU Time value
592  */
593  void GetUserUsedTime(unsigned long* outUserTime)
594  {
595  *outUserTime = lu_utime;
596  }
597 
598 /**
599  * @brief This function gives information about System used CPU time.
600  *
601  * - System time is the amount of time the CPU was busy executing code in kernel space.
602  *
603  * @param[out] outSystemTime Output System used CPU Time value
604  */
605  void GetSystemUsedTime(unsigned long* outSystemTime)
606  {
607  *outSystemTime = lu_stime;
608  }
609 
610 /**
611  * @brief This function gives the information about Total Major Faults.
612  *
613  * - The number of major faults the process has made which required loading a memory page from disk.
614  *
615  * @param[out] outTotalMjrFlts Outputs Total Major Faults
616  */
617  void GetTotalMjrFlts(unsigned int* outTotalMjrFlts)
618  {
619  *outTotalMjrFlts = lu_majflt;// + lu_cmajflt;
620  }
621 };
622 
623 /**
624  * @brief This function gives Current Date and Time in the format Year-Month-Day and Hours-Minutes-Seconds.
625  *
626  * @ret Returns date and time in string format.
627  */
629 {
630  time_t rawtime;
631  tm* timeinfo;
632 
633  time(&rawtime);
634  timeinfo = localtime(&rawtime);
635 
636  strftime(strTime,80,"%Y-%m-%d %H:%M:%S",timeinfo);
637  return strTime;
638 }
639 
640 /**
641  * @brief This function gives information about the Memory parameters.
642  *
643  * - Information such as Virtual Memory Size, Resident Set Size and Size Of Stack
644  *
645  * @param[in] filename Name of the File
646  * @param[out] memParam Memory Parameters
647  * @param[in] param It can be parameter like Virtual Memory Size, Resident Set Size and Size Of Stack.
648  */
649 void GetMemParams(char* filename, unsigned long* memParam, char* param)
650 {
651  char line[128]= {'\0'};
652 
653  string str;
654  FILE* fp_status = fopen(filename, "r");
655  if(fp_status)
656  {
657  while(!feof(fp_status))
658  {
659  fgets(line, sizeof(line)-1, fp_status);
660  if(strncmp(line, param, strlen(param)) == 0)
661  {
662  stringstream ss(line);
663  for (int idx=0; idx<2; idx++)
664  ss >> str;
665  *memParam = atoi(str.c_str());
666  break;
667  }
668  memset(line,0,sizeof(line));
669  }
670  fclose(fp_status);
671  }
672  else
673  {
674  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): ERROR opening the file: %s\n", __func__, __LINE__, filename);
675  }
676 }
677 
678 /**
679  * @brief This function gives Load Average values.
680  *
681  * Output Example = 0.75 0.33 0.25 1/25 1747 where :
682  *
683  * - First three fields : Load averages over the last 1,5 and 15 minutes.
684  * - The fourth field consists of two numbers separated by a slash (/), where :
685  * First number is the number of currently executing kernel scheduling entities(processes,threads);
686  * this will be less than or equal to the number of CPUs.
687  * - The value after the slash is the number of kernel scheduling entities that currently exist on the system.
688  * - The fifth field is the PID of the process.
689  *
690  * @param[out] loadavg Load Average value
691  */
692 void GetLoadAverage(float* loadavg)
693 {
694  //Capture Load Average value
695  FILE *fp;
696  if ((fp = fopen("/proc/loadavg", "r")) == NULL)
697  {
698  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): ERROR reading file: /proc/loadavg", __func__, __LINE__);
699  }
700  else
701  {
702  fscanf(fp, "%f", loadavg);
703  fclose(fp);
704  }
705 }
706 
707 /**
708  * @brief This function gives information about Used memory.
709  *
710  * - It reports statistics about memory usage on the system and gives information like Total usable RAM and Free Memory.
711  * - Used Memory is calculated by subtracting Free Memory from Total Memory.
712  *
713  * @param[out] mem Used Memory value
714  */
715 void GetUsedMemory(unsigned long* mem)
716 {
717  //Capture Used Memory value
718  char line[64]= {'\0'};
719  string str;
720  int count=0;
721  unsigned long memTotal = 0;
722  unsigned long memFree = 0;
723  FILE* fp = fopen("/proc/meminfo", "r");
724  if(fp)
725  {
726  while(!feof(fp))
727  {
728  fgets(line, sizeof(line), fp);
729  if(strncmp(line, "MemTotal:", 8) == 0)
730  {
731  stringstream ss(line);
732  for (int idx=0; idx<2; idx++)
733  ss >> str;
734  memTotal = atoi(str.c_str());
735  count++;
736  }
737  else if(strncmp(line, "MemFree:", 7) == 0)
738  {
739  stringstream ss(line);
740  for (int idx=0; idx<2; idx++)
741  ss >> str;
742  memFree = atoi(str.c_str());
743  count++;
744  }
745  if(count == 2) break;
746  memset(line,0,sizeof(line));
747  }
748  *mem = memTotal - memFree;
749  fclose(fp);
750  }
751  else
752  {
753  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): ERROR opening the file: /proc/meminfo\n", __func__, __LINE__);
754  }
755 }
756 
757 /**
758  * @brief This function gives the Idle percent value.
759  *
760  * - Idle time is the amount of time the CPU was not busy or otherwise, the amount of time it executed the System Idle process.
761  * - Idle time actually measures unused CPU capacity.
762  *
763  * @param[out] idlepercent Idle Percent Value
764  */
765 void GetIdlePercent(float* idlePercent)
766 {
767  char buf[320];
768  unsigned long u, n, s, i, w, x, y, z;
769  stCPUInfo currentCPUInfo;
770  FILE* fp = fopen("/proc/stat", "r");
771  if(fp)
772  {
773  fgets(buf, sizeof(buf), fp);
774  sscanf(buf, "cpu %lu %lu %lu %lu %lu %lu %lu %lu", &u, &n, &s, &i, &w, &x, &y, &z);
775  currentCPUInfo.total = u + n + s + i + w + x + y + z;
776  currentCPUInfo.idle = i;
777 
778  *idlePercent = (float)(100 * (currentCPUInfo.idle - prevCPUInfo.idle)/(currentCPUInfo.total - prevCPUInfo.total));
779 
780  prevCPUInfo.total = currentCPUInfo.total;
781  prevCPUInfo.idle = currentCPUInfo.idle;
782  }
783  fclose(fp);
784 }
785 
786 /**
787  * @brief This function to exclude the process list of least concern.
788  */
790 {
791  char tmp_string[32];
792  sprintf(tmp_string,"cd ../../bin");
793  system(tmp_string);
794  sprintf(tmp_string,"busybox --list");
795  FILE * fp = popen( tmp_string, "r" );
796  if ( fp == 0 ) {
797  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Could not get busy box list\n");
798  return;
799  }
800  char buf1[ BUFF_SIZE_64 ];
801  while(fgets(buf1,BUFF_SIZE_64,fp)!= NULL)
802  {
803  buf1[strlen(buf1) - 1] = '\0';
804  exclude_process_list.push_back(string(buf1));
805  memset(buf1,0,sizeof(buf1));
806  }
807  pclose(fp);
808  //exclude_process_list.push_back("cpuprocanalyzer");
809 }
810 
811 /**
812  * @brief This function gives information about the File Descriptors in process.
813  *
814  * @param[in] d_pid PID of process
815  * @param[in] FDCount File Descriptor in process
816  */
817 void GetFDCount(char* filename, int* FDCount)
818 
819 {
820  FILE * fp = popen( filename, "r" );
821 
822  if ( fp == 0 )
823  {
824  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Could not get FD Count\n");
825  }
826  else
827  {
828  fscanf(fp, "%d" , FDCount);
829  pclose(fp);
830  }
831 }
832 
833 /**
834  * @brief This function gives information about the File Descriptors at system level.
835  *
836  * @param[in] FDCountSystem File Descriptors at system level
837 */
838 
839 void GetFDCountSystem(int* FDCountSystem)
840 
841 {
842  char tmp_string[64] = {0};
843  snprintf(tmp_string, sizeof(tmp_string), "/proc/sys/fs/file-nr" );
844  FILE * fp = fopen( tmp_string, "r" );
845 
846  if ( fp == 0 )
847  {
848  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Could not get FD Count System Level\n");
849  }
850  else
851  {
852  fscanf(fp, "%d" , FDCountSystem);
853  fclose(fp);
854  }
855 }
856 
857 /**
858  * @brief This is to set the bit mask for System/Process.
859 */
860 
861 uint SetMask(char* res)
862 {
863  uint bit_mask = 0x00;
864  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Input param = %s, strlen(res) = %d, sizeof() = %d\n",
865  res, strlen(res), sizeof(res));
866 
867  char *newline = strchr( res, '\n' );
868  if ( newline )
869  {
870  *newline = '\0';
871  }
872 
873  char *token = strtok(res, ",");
874  while(token != NULL)
875  {
876  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Token = %s, Strlen = %d, sizeof() = %d\n", token, strlen(token), sizeof(token));
877  if(strncmp(token,"cpu",strlen(token)) == 0)
878  {
879  bit_mask |= CPU_MASK;
880  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Cpu mask is set : %d\n", bit_mask);
881  }
882  else if(strncmp(token,"memory",strlen(token)) == 0)
883  {
884  bit_mask |= MEMORY_MASK;
885  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Memory mask is set : %d\n", bit_mask);
886  }
887  else if(strncmp(token,"fd",strlen(token)) == 0)
888  {
889  bit_mask |= FDCOUNT_MASK;
890  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","FD mask is set : %d\n", bit_mask);
891  }
892  else if(strncmp(token,"loadavg",strlen(token)) == 0)
893  {
894  bit_mask |= LOADAVG_MASK;
895  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","LoadAvg mask is set : %d\n", bit_mask);
896  }
897  else if(strncmp(token,"thread",strlen(token)) == 0)
898  {
899  bit_mask |= THREADCOUNT_MASK;
900  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Thread mask is set : %d\n", bit_mask);
901  }
902  else if(strncmp(token,"cliconnected",strlen(token)) == 0)
903  {
904  bit_mask |= CLICOUNT_MASK;
905  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Cli count mask is set : %d\n", bit_mask);
906  }
907  token = strtok(NULL, ",");
908  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","token is : %s\n", token);
909  }
910  return bit_mask;
911 }
912 
913 /**
914  * @brief This function gives status information about the process.
915  *
916  * - Information such as Process Name, PID of the parent, Virtual memory size, Resident set size, Size of Stack.
917  *
918  * @param[in] procData Process Data
919  * @param[in] ppid Parent pid,default to 0
920  * @param[in] pname Parent Name
921  * @param[in] is_dynamic Flag to check dynamically created process.
922  */
923 int LogProcData(stProcData* procData, int ppid=0, char* pname="",int is_dynamic=0, bool telemetryOnly=0)
924 {
925  char tmp_string[1024] = {0};
926  unsigned long vmStack=0;
927  unsigned long vmSize=0;
928  unsigned long vmRSS=0;
929  int return_val;
930  int FDCount=0;
931  string searchstr = ".sh";
932  string searchstr_1 = "kworker";
933  string s;
934  memset(tmp_string,0,1024);
935  (ppid != 0) ? sprintf(tmp_string, "/proc/%d/task/%d/stat", ppid, procData->d_pid)
936  : sprintf(tmp_string, "/proc/%d/stat", procData->d_pid);
937 
938  fp_stat = fopen(tmp_string, "r");
939  if(fp_stat) {
940  procData->ReadProcStat(fp_stat);
941  fclose(fp_stat);
942  }
943  else
944  {
945  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Failed to open %s file\n", tmp_string);
946  return 0;
947  }
948 
949  // excluding processes of least concern
950  if(ppid!= 0)
951  {
952  for(it=exclude_process_list.begin();it!=exclude_process_list.end();it++)
953  {
954  s= *it;
955  if(strncmp(procData->s_comm,s.c_str(),MAX(strlen(procData->s_comm),strlen(s.c_str()))) == 0)
956  {
957  return 0;
958  }
959  }
960  }
961  //process
962  else
963  {
964  if(strlen(procData->s_comm) == 0)
965  {
966  return 0;
967  }
968  else
969  {
970  for(it=exclude_process_list.begin();it!=exclude_process_list.end();it++)
971  {
972  s = *it;
973  if(strncmp(procData->s_comm,s.c_str(),MAX(strlen(procData->s_comm),strlen(s.c_str()))) == 0)
974  {
975  return 0;
976  }
977  }
978  }
979  }
980 
981  if(PROC_MASK & MEMORY_MASK)
982  {
983  (ppid != 0) ? sprintf(tmp_string, "/proc/%d/task/%d/status", ppid, procData->d_pid)
984  : sprintf(tmp_string, "/proc/%d/status", procData->d_pid);
985  GetMemParams(tmp_string, &vmStack, "VmStk:");
986  GetMemParams(tmp_string, &vmSize, "VmSize:");
987  GetMemParams(tmp_string, &vmRSS, "VmRSS:");
988  }
989  if(PROC_MASK & FDCOUNT_MASK)
990  {
991  (ppid != 0) ? snprintf(tmp_string, sizeof(tmp_string), "ls /proc/%d/task/%d/fd | wc -l", ppid, procData->d_pid)
992  : snprintf(tmp_string, sizeof(tmp_string), "ls /proc/%d/fd | wc -l", procData->d_pid);
993  GetFDCount(tmp_string, &FDCount);
994  }
995 
996 
997  /*
998  Possible cases from /proc/<pid>/cmdline that confirms a script running
999  1. /bin/sh <script>
1000  2. /bin/bash <script>
1001  2. sh <script>
1002  3. -sh
1003  4. -bash
1004  Substring sh in processname can be cross verified with the presence of "sh" in /proc/<pid>/comm
1005  */
1006  sprintf(tmp_string, "/proc/%d/cmdline", procData->d_pid);
1007  FILE* fp_cmd = fopen(tmp_string, "r");
1008  if(fp_cmd)
1009  {
1010  fgets(tmp_string, sizeof(tmp_string), fp_cmd);
1011  fclose(fp_cmd);
1012 
1013  if ( (strncmp(tmp_string,"/bin/sh",strlen(tmp_string)) == 0) ||
1014  (strncmp(tmp_string,"sh",strlen(tmp_string)) ==0 ) ||
1015  (strncmp(tmp_string,"-sh",strlen(tmp_string)) == 0) ||
1016  (strncmp(tmp_string,"-bash",strlen(tmp_string)) == 0) ||
1017  (strncmp(tmp_string,"/bin/bash",strlen(tmp_string)) == 0) )
1018  {
1019  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER","Rejecting process : %s\n", procData->s_comm);
1020  return 0;
1021  } else if ( strstr(tmp_string,searchstr.c_str()) ) {
1022  sprintf(tmp_string, "/proc/%d/comm", procData->d_pid);
1023  FILE* fp_cmd = fopen(tmp_string, "r");
1024  if(fp_cmd)
1025  {
1026  fgets(tmp_string, sizeof(tmp_string), fp_cmd);
1027  fclose(fp_cmd);
1028  if( (strncmp(tmp_string,"sh",strlen(tmp_string)) == 0) || (strncmp(tmp_string,"bash",strlen(tmp_string)) == 0) )
1029  {
1030  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER","Rejecting process : %s\n", procData->s_comm);
1031  return 0;
1032  }
1033  }
1034  }
1035  }
1036 
1037  /* Reject kworker_threads */
1038  sprintf(tmp_string, "/proc/%d/comm", procData->d_pid);
1039  fp_cmd = fopen(tmp_string, "r");
1040  if(fp_cmd)
1041  {
1042  fgets(tmp_string, sizeof(tmp_string), fp_cmd);
1043  fclose(fp_cmd);
1044  if( strstr(tmp_string,searchstr_1.c_str()) )
1045  {
1046  return 0;
1047  }
1048  }
1049 
1050  if (ppid != 0) {
1051  sprintf(tmp_string, "%s/%d_%s/threads/", outputDir.c_str(), ppid, pname);
1052  }
1053  else
1054  {
1055  if(is_dynamic == 0)
1056  {
1057  sprintf(tmp_string, "%s%d_%s", outputDir.c_str(), procData->d_pid, procData->s_comm);
1058 
1059  }
1060  else
1061  {
1062  sprintf(tmp_string, "%s%d_%s", outputDynamicDir.c_str(), procData->d_pid, procData->s_comm);
1063  }
1064  }
1065 
1066  mkdir(tmp_string, S_IRWXU | S_IRWXG | S_IRWXO);
1067  (ppid != 0) ? procData->OutFilename(tmp_string, ppid, pname) : procData->OutFilename(tmp_string,is_dynamic);
1068  fp_dataOut = fopen(tmp_string, "a+");
1069  if(fp_dataOut)
1070  {
1071  unsigned long currentTotalUsedCPUTime = 0;
1072  unsigned int currentTotalMajorFaultsRaised = 0;
1073  unsigned long currentUserUsedCPUTime = 0;
1074  unsigned long currentSystemUsedCPUTime = 0;
1075  struct timeval currentTime;
1076  double currentTime_usec, timeDiff_usec, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System;
1077  unsigned int majorFaultsRaise;
1078 
1079  procData->GetTotalUsedTime(&currentTotalUsedCPUTime);
1080  procData->GetUserUsedTime(&currentUserUsedCPUTime);
1081  procData->GetSystemUsedTime(&currentSystemUsedCPUTime);
1082  procData->GetTotalMjrFlts(&currentTotalMajorFaultsRaised);
1083  gettimeofday(&currentTime, NULL);
1084  currentTime_usec = (currentTime.tv_sec*1000000.0)+currentTime.tv_usec;
1085 
1086  timeDiff_usec = currentTime_usec - prevData[procData->d_pid].prevTotalCPUTime_usec;
1087  if(timeDiff_usec == 0) timeDiff_usec = 1;
1088  cpuUseRaise = 100*(currentTotalUsedCPUTime - prevData[procData->d_pid].prevTotalUsedCPUTime)/(sysconf(_SC_CLK_TCK)*timeDiff_usec/1000000);
1089  cpuUseRaise_User = 100*(currentUserUsedCPUTime - prevData[procData->d_pid].prevUserUsedCPUTime)/(sysconf(_SC_CLK_TCK)*timeDiff_usec/1000000);
1090  cpuUseRaise_System = 100*(currentSystemUsedCPUTime - prevData[procData->d_pid].prevSystemUsedCPUTime)/(sysconf(_SC_CLK_TCK)*timeDiff_usec/1000000);
1091  if(ppid == 0)
1092  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %d %0.2lf %0.2lf %0.2lf %ld %ld %0.2lf %0.2lf\n", __func__, __LINE__, procData->d_pid, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, currentTotalUsedCPUTime, prevData[procData->d_pid].prevTotalUsedCPUTime, sysconf(_SC_CLK_TCK), timeDiff_usec);
1093  majorFaultsRaise = (currentTotalMajorFaultsRaised - prevData[procData->d_pid].prevTotalMajFaultsRaised);
1094 
1095  prevData[procData->d_pid].prevTotalUsedCPUTime = currentTotalUsedCPUTime;
1096  prevData[procData->d_pid].prevUserUsedCPUTime = currentUserUsedCPUTime;
1097  prevData[procData->d_pid].prevSystemUsedCPUTime = currentSystemUsedCPUTime;
1098  prevData[procData->d_pid].prevTotalCPUTime_usec = currentTime_usec;
1099  prevData[procData->d_pid].prevTotalMajFaultsRaised = currentTotalMajorFaultsRaised;
1100 
1101  if(prevData[procData->d_pid].status != 1)
1102  {
1103  sprintf(tmp_string, "/proc/%d/cmdline", procData->d_pid);
1104  FILE* fp_cmd = fopen(tmp_string, "r");
1105  if(fp_cmd)
1106  {
1107  ReadSkippingRandomChar(fp_cmd, tmp_string);
1108  fclose(fp_cmd);
1109 
1110  if(telemetryOnly == false)
1111  {
1112  fprintf(fp_dataOut, "Command-Line : %s\n\n", tmp_string);
1113  if(PROC_MASK)
1114  {
1115  fprintf(fp_dataOut, "El-Time\tTimeStamp\t");
1116  if(PROC_MASK & CPU_MASK)
1117  {
1118  fprintf(fp_dataOut, "\tCPU%\tCPU%:U\tCPU%:S\tMjrFlts");
1119  }
1120  if(PROC_MASK & MEMORY_MASK)
1121  {
1122  fprintf(fp_dataOut, "\tVmSize\tVmRSS\tVmStk");
1123  }
1124  if(PROC_MASK & THREADCOUNT_MASK)
1125  {
1126  fprintf(fp_dataOut, "\tThreadCount");
1127  }
1128  if(PROC_MASK & FDCOUNT_MASK)
1129  {
1130  fprintf(fp_dataOut, "\tFDCount");
1131  }
1132  fprintf(fp_dataOut, "\n");
1133  }
1134  else
1135  {
1136  fprintf(fp_dataOut, "El-Time\tTimeStamp\t\tCPU%\tCPU%:U\tCPU%:S\tMjrFlts\tVmSize\tVmRSS\tVmStk\tThreadCount\tFDCount\n");
1137  }
1138  }
1139  }
1140  }
1141 
1142  if(is_dynamic ==1 )
1143  {
1144  sprintf(tmp_string, "/proc/%d/stat", procData->d_pid);
1145  FILE *f = fopen(tmp_string, "r");
1146  if ( f == 0 ) {
1147  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Failed to open /proc/%d/stat/ of dynamic process\n", procData->d_pid);
1148  return 0;
1149  }
1150  else {
1151  fscanf(f, " %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %llu %lu %ld %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld", &procData->c_state, &procData->d_ppid, &procData->d_pgrp, &procData->d_session, &procData->d_tty_nr, &procData->d_tpgid, &procData->u_flags, &procData->lu_minflt, &procData->lu_cminflt, &procData->lu_majflt, &procData->lu_cmajflt, &procData->lu_utime, &procData->lu_stime, &procData->ld_cutime, &procData->ld_cstime, &procData->ld_priority, &procData->ld_nice, &procData->ld_num_threads, &procData->ld_itrealvalue, &procData->llu_starttime, &procData->lu_vsize, &procData->ld_rss, &procData->lu_rsslim, &procData->lu_startcode, &procData->lu_endcode, &procData->lu_startstack, &procData->lu_kstkesp, &procData->lu_kstkeip, &procData->lu_signal, &procData->lu_blocked, &procData->lu_sigignore, &procData->lu_sigcatch, &procData->lu_wchan, &procData->lu_nswap, &procData->lu_cnswap, &procData->d_exit_signal, &procData->d_processor, &procData->u_rt_priority, &procData->u_policy, &procData->llu_delayacct_blkio_ticks, &procData->lu_guest_time,&procData->ld_cguest_time);
1152  cpuUseRaise= procData->lu_utime + procData->lu_stime;
1153  cpuUseRaise_User = procData->lu_utime;
1154  cpuUseRaise_System = procData->lu_stime;
1155 
1156  if(telemetryOnly == false)
1157  {
1158  if(PROC_MASK)
1159  {
1160  fprintf(fp_dataOut, "%ld\t%s", totalTimeElapsed_sec, GetCurTimeStamp());
1161  if(PROC_MASK & CPU_MASK)
1162  {
1163  fprintf(fp_dataOut, "\t%0.2lf\t%0.2lf\t%0.2lf\t%d", cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise);
1164  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %0.2lf %0.2lf %0.2lf %d \n", __func__, __LINE__, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise);
1165  }
1166  if(PROC_MASK & MEMORY_MASK)
1167  {
1168  fprintf(fp_dataOut, "\t%ld\t%ld\t%ld", vmSize, vmRSS, vmStack);
1169  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %ld %ld %ld \n", __func__, __LINE__, vmSize, vmRSS, vmStack);
1170  }
1171  if(PROC_MASK & THREADCOUNT_MASK)
1172  {
1173  fprintf(fp_dataOut, "\t%ld\t", ((procData->ld_num_threads)-1));
1174  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %ld \n", __func__, __LINE__, ((procData->ld_num_threads)-1));
1175  }
1176  if(PROC_MASK & FDCOUNT_MASK)
1177  {
1178  fprintf(fp_dataOut, "\t%d\t", FDCount);
1179  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %d \n", __func__, __LINE__, FDCount);
1180  }
1181  fprintf(fp_dataOut, "\n");
1182  }
1183  else
1184  {
1185  fprintf(fp_dataOut, "%ld\t%s\t%0.2lf\t%0.2lf\t%0.2lf\t%d\t%ld\t%ld\t%ld\t%ld\t\t%d\t\n", totalTimeElapsed_sec, GetCurTimeStamp(), cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise, vmSize, vmRSS, vmStack, ((procData->ld_num_threads)-1), FDCount);
1186  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %0.2lf %0.2lf %0.2lf %d %ld %ld %ld %ld %d \n", __func__, __LINE__, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise, vmSize, vmRSS, vmStack, ((procData->ld_num_threads)-1), FDCount);
1187  }
1188  }
1189  }
1190  fclose(f);
1191  }
1192 
1193  if(prevData[procData->d_pid].status)
1194  {
1195  if(telemetryOnly == false)
1196  {
1197  if(PROC_MASK)
1198  {
1199  fprintf(fp_dataOut, "%ld\t%s", totalTimeElapsed_sec, GetCurTimeStamp());
1200  if(PROC_MASK & CPU_MASK)
1201  {
1202  fprintf(fp_dataOut, "\t%0.2lf\t%0.2lf\t%0.2lf\t%d", cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise);
1203  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %0.2lf %0.2lf %0.2lf %d \n", __func__, __LINE__, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise);
1204  }
1205  if(PROC_MASK & MEMORY_MASK)
1206  {
1207  fprintf(fp_dataOut, "\t%ld\t%ld\t%ld", vmSize, vmRSS, vmStack);
1208  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %ld %ld %ld \n", __func__, __LINE__, vmSize, vmRSS, vmStack);
1209  }
1210  if(PROC_MASK & THREADCOUNT_MASK)
1211  {
1212  fprintf(fp_dataOut, "\t%ld\t", ((procData->ld_num_threads)-1));
1213  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %ld \n", __func__, __LINE__, ((procData->ld_num_threads)-1));
1214  }
1215  if(PROC_MASK & FDCOUNT_MASK)
1216  {
1217  fprintf(fp_dataOut, "\t%d\t", FDCount);
1218  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %d \n", __func__, __LINE__, FDCount);
1219  }
1220  fprintf(fp_dataOut, "\n");
1221  }
1222  else
1223  {
1224  fprintf(fp_dataOut, "%ld\t%s\t%0.2lf\t%0.2lf\t%0.2lf\t%d\t%ld\t%ld\t%ld\t%ld\t\t%d\t\n", totalTimeElapsed_sec, GetCurTimeStamp(), cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise, vmSize, vmRSS, vmStack, ((procData->ld_num_threads)-1), FDCount);
1225  RDK_LOG(RDK_LOG_TRACE1, "LOG.RDK.CPUPROCANALYZER", "%s(%d): %0.2lf %0.2lf %0.2lf %d %ld %ld %ld %ld %d \n", __func__, __LINE__, cpuUseRaise, cpuUseRaise_User, cpuUseRaise_System, majorFaultsRaise, vmSize, vmRSS, vmStack, ((procData->ld_num_threads)-1), FDCount);
1226  }
1227  }
1228  }
1229  fclose(fp_dataOut);
1230 
1231  #if defined PROCANALYZER_BROADBAND
1232  //Telemetry event send
1233  if(ppid == 0)
1234  {
1235  char eventName[32]={'\0'};
1236  char telemetry_buf[128] = {'\0'};
1237  snprintf(eventName, sizeof(eventName), "CPA_INFO_%s", procData->s_comm);
1238  snprintf(telemetry_buf, sizeof(telemetry_buf), "%ld,%0.2lf,%d,%d", vmRSS, cpuUseRaise, FDCount, procData->ld_num_threads-1);
1239  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Event : %s, Value : %s\n", eventName, telemetry_buf);
1240  t2_event_s(eventName, telemetry_buf);
1241  }
1242  #endif
1243  }
1244  else
1245  {
1246  if(telemetryOnly == false)
1247  {
1248  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","%s(%d): ERROR opening the file: %s\n", __func__, __LINE__, tmp_string);
1249  }
1250  return 0;
1251  }
1252 
1253  prevData[procData->d_pid].status = 1;
1254  return 1;
1255 }
1256 
1257 static volatile bool need_exit = false;
1258 
1259 /*
1260  * @brief Connect to netlink
1261  * returns netlink socket, or -1 on error
1262  */
1263 static int netlink_connect()
1264 {
1265  int rc;
1266  int netlink_sock;
1267  struct sockaddr_nl nl_sockaddr;
1268 
1269  netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
1270  if (netlink_sock == -1) {
1271  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Failed to create socket. Error code = %d \n", errno);
1272  return -1;
1273  }
1274 
1275  nl_sockaddr.nl_family = AF_NETLINK;
1276  nl_sockaddr.nl_groups = CN_IDX_PROC;
1277  nl_sockaddr.nl_pid = getpid();
1278 
1279  rc = bind(netlink_sock, (struct sockaddr *)&nl_sockaddr, sizeof(nl_sockaddr));
1280  if (rc == -1) {
1281  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","bind operation failed, closing the socket\n");
1282  close(netlink_sock);
1283  return -1;
1284  }
1285 
1286  return netlink_sock;
1287 }
1288 
1289 /*
1290  * @brief subscribe for netlink process events by setting it to multicast listen mode
1291  */
1292 static int subscribe_proc_events(int netlink_sock, bool enable)
1293 {
1294  int retCode;
1295  struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
1296  struct nlmsghdr nl_header;
1297  struct __attribute__ ((__packed__)) {
1298  struct cn_msg cn_message;
1299  enum proc_cn_mcast_op cn_mcast;
1300  };
1301  }
1302  netlink_msg;
1303 
1304  memset(&netlink_msg, 0, sizeof(netlink_msg));
1305  netlink_msg.nl_header.nlmsg_len = sizeof(netlink_msg);
1306  netlink_msg.nl_header.nlmsg_pid = getpid();
1307  netlink_msg.nl_header.nlmsg_type = NLMSG_DONE;
1308 
1309  netlink_msg.cn_message.id.idx = CN_IDX_PROC;
1310  netlink_msg.cn_message.id.val = CN_VAL_PROC;
1311  netlink_msg.cn_message.len = sizeof(enum proc_cn_mcast_op);
1312 
1313  netlink_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
1314 
1315  retCode = send(netlink_sock, &netlink_msg, sizeof(netlink_msg), 0);
1316  if (retCode == -1) {
1317  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","netlink send failed\n");
1318  return -1;
1319  }
1320 
1321  return 0;
1322 }
1323 
1324 /*
1325  * @brief handle net link process events and identify newly forked or executing process
1326  */
1327 
1328 static int handle_process_events(int netlink_sock)
1329 {
1330  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER"," handle proc ev entered \n");
1331  int retCode;
1332  stProcData dProcData;
1333 
1334  struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
1335  struct nlmsghdr nl_header;
1336  struct __attribute__ ((__packed__)) {
1337  struct cn_msg cn_message;
1338  struct proc_event process_event;
1339  };
1340  }
1341  netlink_msg;
1342 
1343  while (!need_exit) {
1344  retCode = recv(netlink_sock, &netlink_msg, sizeof(netlink_msg), 0);
1345  memset(&dProcData,0,sizeof(dProcData));
1346  if (retCode == 0) {
1347  /* shutdown? */
1348  return 0;
1349  } else if (retCode == -1) {
1350  if (errno == EINTR) continue;
1351  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","netlink recv failed \n");
1352  return -1;
1353  }
1354  switch (netlink_msg.process_event.what) {
1355  case PROC_EVENT_NONE:
1356  RDK_LOG(RDK_LOG_DEBUG,"LOG.RDK.CPUPROCANALYZER","Setting Multicast listen success.\n");
1357  break;
1358  // Received a fork event from netlink socket
1359  case PROC_EVENT_FORK:
1360  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER","Forked new proc : form parent TID=%d PID=%d => child TID=%d PID=%d\n",
1361  netlink_msg.process_event.event_data.fork.parent_pid,
1362  netlink_msg.process_event.event_data.fork.parent_tgid,
1363  netlink_msg.process_event.event_data.fork.child_pid,
1364  netlink_msg.process_event.event_data.fork.child_tgid);
1365  dProcData.d_pid = netlink_msg.process_event.event_data.fork.child_pid;
1366  pthread_mutex_lock(&mtx);
1367  LogProcData(&dProcData,0,"",1);
1368  pthread_mutex_unlock(&mtx);
1369  break;
1370  // Received an exec event from netlink socket
1371  case PROC_EVENT_EXEC:
1372  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER","Exec Proc: TID=%d PID=%d\n",
1373  netlink_msg.process_event.event_data.exec.process_pid,
1374  netlink_msg.process_event.event_data.exec.process_tgid);
1375  break;
1376  default:
1377  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER","unhandled nelink proc event\n");
1378  break;
1379  }
1380  }
1381  return 0;
1382 }
1383 
1384 /*
1385 *
1386 * Thread for handling dynamic process based on netlink process events
1387 *
1388 */
1389 static void *handle_proc_ev_thread(void *arg )
1390 {
1391  int netlink_sock = netlink_connect();
1392  if(netlink_sock == -1)
1393  {
1394  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Failed to create netlink socket \n");
1395  return NULL;
1396  }
1397  int rc = subscribe_proc_events(netlink_sock, true);
1398  if(rc == -1)
1399  {
1400  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER"," Setting of event listen failed \n");
1401  close(netlink_sock);
1402  return NULL;
1403  }
1404  rc = handle_process_events(netlink_sock);
1405  if(rc == -1)
1406  {
1407  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Subscription request failed\n");
1408  }
1409  return NULL;
1410 }
1411 
1412 
1413 int checkifdigit(char* ch,int size)
1414 {
1415  int retid = 1;
1416  int i;
1417  for(i=0;i<size;i++)
1418  {
1419  if(isdigit(*ch))
1420  {
1421  continue;}
1422  else
1423  {
1424  retid = 0;
1425  break;
1426  }
1427  ch=ch+1;
1428  }
1429  return retid;
1430 }
1431 
1432 bool CheckMemLimit (int itr, unsigned long memLimit)
1433 {
1434  char buf1[BUFF_SIZE_64]={0};
1435  static int prev_mem=0;
1436  int size_diff=0;
1437  int cur_mem=0;
1438  char tmp_filename[128]={0};
1439  sprintf(tmp_filename,"du -s %s | awk '{print$1}'",outputDir.c_str());
1440 
1441  FILE * fp = popen(tmp_filename, "r");
1442 
1443  if (fp == 0)
1444  {
1445  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): popen failed.Failed to read tmp details.\n", __func__, __LINE__);
1446  return false;
1447  }
1448 
1449  memset(buf1, 0, BUFF_SIZE_64);
1450  fgets(buf1, BUFF_SIZE_64, fp);
1451  pclose(fp);
1452 
1453  cur_mem=atoi(buf1);
1454  if (itr!=2)
1455  {
1456  size_diff=(cur_mem - prev_mem);
1457  }
1458  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Mem Limits curr : %d | prev : %d | diff : %d\n", cur_mem, prev_mem, size_diff);
1459  prev_mem=cur_mem;
1460 
1461  if ((cur_mem + size_diff) >= memLimit)
1462  return false;
1463  return true;
1464 }
1465 
1466 /**
1467  * @brief Main Function.
1468  *
1469  * Fetches information such as Load Average value, Used Memory value and Idle Percent value for all the Processes in the list from /opt/logs/cpuprocanalyzer/loadandmem.data.
1470  */
1471 int main(int argc, char** argv)
1472 {
1473 
1474  const char* pDebugConfig = NULL;
1475  const char* pEnvConfig = NULL;
1476  const char* DEBUG_ACTUAL_PATH = "/etc/debug.ini";
1477  const char* ENV_ACTUAL_PATH = "/etc/procanalyzerconfig.ini";
1478  const char* ENV_OVERRIDE_PATH = CONFIG_PATH"/procanalyzerconfig.ini";
1479  const char* DEBUG_OVERRIDE_PATH = CONFIG_PATH"/debug.ini";
1480  const char* PROCESSES_LIST_PATH = CONFIG_PATH"/processes.list";
1481  int iteration = 0;
1482  int pCount = 0;
1483 
1484  int returncode = EXIT_SUCCESS;
1485  string dynamicFolder;
1486  int returnid;
1487  pthread_t process_handler_tid;
1488  #ifndef PROCANALYZER_EXTENDER
1489  if (access(DEBUG_OVERRIDE_PATH, F_OK) != -1)
1490  pDebugConfig = DEBUG_OVERRIDE_PATH;
1491  else
1492  pDebugConfig = DEBUG_ACTUAL_PATH;
1493 
1494  rdk_logger_init(pDebugConfig);
1495  #endif
1496  if (access(ENV_OVERRIDE_PATH, F_OK) != -1)
1497  pEnvConfig = ENV_OVERRIDE_PATH;
1498  else
1499  pEnvConfig = ENV_ACTUAL_PATH;
1500 
1501  #if defined PROCANALYZER_BROADBAND
1502  t2_init("cpuprocanalyzer");
1503  #endif
1504 
1505  char tmp_string[256]={0};
1506  unsigned long timeToRun_sec ;
1507  unsigned int sleepInterval_ms;
1508  unsigned long memoryLimit;
1509  bool monitorAllProcess = false;
1510  bool enableDynamic = true;
1511  bool telemetryOnly = false;
1512  string grepProcesses;
1513  int env;
1514  char* ptr;
1515  char res[64];
1516  string ps_filename = outputDir + "selectedps.list";
1517  memset(res,0,64);
1518  ((env=read_config_param("FEATURE.CPUPROCANALYZER.SleepInterval",pEnvConfig,res)) == 0) ? sleepInterval_ms = SLEEP_SECS*1000 : sleepInterval_ms = strtol(res,&ptr,10)*1000;
1519  memset(res,0,64);
1520  ((env=read_config_param("FEATURE.CPUPROCANALYZER.TimeToRun",pEnvConfig,res)) == 0) ? timeToRun_sec = TIME_TO_RUN_SECS : timeToRun_sec = strtol(res,&ptr,10);
1521  memset(res,0,64);
1522  ((env=read_config_param("FEATURE.CPUPROCANALYZER.DynamicProcess",pEnvConfig,res)) == 0) ? enableDynamic = DEFAULT_DYNAMIC : enableDynamic = res[0] - '0';
1523  memset(res,0,64);
1524  ((env=read_config_param("FEATURE.CPUPROCANALYZER.MonitorAllProcess",pEnvConfig,res)) == 0) ? monitorAllProcess = MONITOR_ALL_PROC_DEF : monitorAllProcess = res[0] - '0';
1525  memset(res,0,64);
1526  ((env=read_config_param("FEATURE.CPUPROCANALYZER.TelemetryOnly",pEnvConfig,res)) == 0) ? telemetryOnly = TELEMETRY_ONLY_DEF : telemetryOnly = res[0] - '0';
1527  memset(res,0,64);
1528  ((env=read_config_param("FEATURE.CPUPROCANALYZER.MemoryLimit",pEnvConfig,res)) == 0) ? memoryLimit = DEFAULT_MEM_THRESHOLD : memoryLimit = strtol(res,&ptr,10);
1529  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","%s(%d):\nSleep Interval(secs): %d\nTime To Run(secs): %ld\n", __func__, __LINE__, sleepInterval_ms/1000, timeToRun_sec);
1530  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Monitor All Process = %d, MemLimit = %ld\nDynamic = %d\ntelemetryOnly = %d\n", monitorAllProcess, memoryLimit, enableDynamic, telemetryOnly);
1531 
1532  #if defined PROCANALYZER_BROADBAND
1533  memset(res,0,64);
1534  if((read_config_param("FEATURE.CPUPROCANALYZER.SystemStatsToMonitor",pEnvConfig,res)) == 0)
1535  {
1536  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYSStats config absent, res value = %s\n", res);
1537  SYS_MASK = SYS_DEF_MASK;
1538  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYSStats config absent, set to DEF MASK = %d\n", SYS_MASK);
1539  }
1540  else
1541  {
1542  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYSStats config present, res value = %s\n", res);
1543  SYS_MASK = SetMask(res);
1544  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYS MASK is set\n");
1545  }
1546 
1547  memset(res,0,64);
1548  if((read_config_param("FEATURE.CPUPROCANALYZER.ProcessStatsToMonitor",pEnvConfig,res)) == 0)
1549  {
1550  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","PROCStats config absent, res value = %s\n", res);
1551  PROC_MASK = PROC_DEF_MASK;
1552  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","PROCStats Config absent, set to DEF MASK = %d\n", PROC_MASK);
1553  }
1554  else
1555  {
1556  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","PROCStats config present, res value = %s\n", res);
1557  PROC_MASK = SetMask(res);
1558  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","PROC MASK is set\n");
1559  }
1560  #endif
1561 
1562  //Clearing the contents of the output directory before running the tool
1563  sprintf(tmp_string, "cd %s && rm -rf *", outputDir.c_str());
1564  system(tmp_string);
1565  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER","Create this directory always: %s\n", tmp_string);
1566  mkdir(outputDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
1567  if(telemetryOnly == false)
1568  {
1569  mkdir(outputDynamicDir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
1570  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER","Creating if telemetryOnly false, outputDynamicDir.c_str()\n");
1571  }
1572  ReadDeviceName();
1574 
1575  #if defined PROCANALYZER_BROADBAND
1576  if(telemetryOnly == false)
1577  {
1578  ReadRFCJson();
1579  }
1580  #endif
1581 
1582  char tmpstring[1024],tmpstring1[128];
1583  char buf1[64],buf2[64];
1584  int val;
1585 
1586  unsigned long long startTime_sec = time(NULL);
1587  unsigned long long currentTime_sec = time(NULL);
1588  unsigned long timeElapsed_sec = 0;
1589  bool terminate = false;
1590  stProcData procData, threadData;
1591 
1592  unsigned int cliCount = 0;
1593  float loadAvg;
1594  unsigned long usedMemory;
1595  float idlePercent;
1596  bool firstIter = true;
1597  bool monitorSysLevel = false;
1598  int FDCountSystem=0;
1599 
1600 
1601  if(enableDynamic) {
1602  returncode = pthread_create(&process_handler_tid,NULL,handle_proc_ev_thread,NULL);
1603 
1604  if (returncode == -1) {
1605  returncode = EXIT_FAILURE;
1606  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","Dynamic process thread creation failed \n");
1607  }
1608  }
1609 
1610  while (iteration++, !terminate && CheckMemLimit (iteration,memoryLimit))/*&& (iteration < ITERATION_THRESHOLD) && CheckMemLimit (iteration))*/
1611  {
1612  //Capture Load Average value
1613  FILE *fp;
1614  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Inside while.....\n");
1615  if(telemetryOnly == false)
1616  {
1617  if(SYS_MASK)
1618  {
1619  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYS MASK NOT NULL, %d\n", SYS_MASK);
1620  if(SYS_MASK & CPU_MASK)
1621  {
1622  GetIdlePercent(&idlePercent);
1623  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Idle: %0.2f\n", __func__, __LINE__, idlePercent);
1624  }
1625  if(SYS_MASK & MEMORY_MASK)
1626  {
1627  GetUsedMemory(&usedMemory);
1628  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Mem: %ld\n", __func__, __LINE__, usedMemory);
1629  }
1630  if(SYS_MASK & FDCOUNT_MASK)
1631  {
1632  GetFDCountSystem(&FDCountSystem);
1633  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): FDCountSystem: %d\n", __func__, __LINE__, FDCountSystem);
1634  }
1635  if(SYS_MASK & LOADAVG_MASK)
1636  {
1637  GetLoadAverage(&loadAvg);
1638  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Load: %0.2f\n", __func__, __LINE__, loadAvg);
1639  }
1640  if(SYS_MASK & CLICOUNT_MASK)
1641  {
1642  GetNumOfClientsConnected(&cliCount);
1643  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): ClientCount: %d\n", __func__, __LINE__, cliCount);
1644  }
1645  }
1646  else
1647  {
1648  RDK_LOG(RDK_LOG_DEBUG, "LOG.RDK.CPUPROCANALYZER","DEFAULT MASK is set\n");
1649  GetIdlePercent(&idlePercent);
1650  GetLoadAverage(&loadAvg);
1651  GetUsedMemory(&usedMemory);
1652  GetFDCountSystem(&FDCountSystem);
1653  GetNumOfClientsConnected(&cliCount);
1654  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Load: %0.2f Mem: %ld \
1655  Idle: %0.2f FDCountSystem: %d ClientCount = %d\n",
1656  __func__, __LINE__, loadAvg, usedMemory, idlePercent,
1657  FDCountSystem, cliCount);
1658  }
1659 
1660  fp = fopen(LOG_PATH"/cpuprocanalyzer/loadandmem.data", "a+");
1661 
1662  if(fp)
1663  {
1664  if(firstIter)
1665  {
1666  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","First Iter = %d\n", firstIter);
1667  if(SYS_MASK)
1668  {
1669  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","SYS_MASK NOT NULL, write data to loadandmem file\n");
1670  fprintf(fp, "TimeStamp\t\t");
1671  if(SYS_MASK & LOADAVG_MASK)
1672  {
1673  fprintf(fp, "LoadAvg\t");
1674  }
1675  if(SYS_MASK & MEMORY_MASK)
1676  {
1677  fprintf(fp, "UsedMem\t");
1678  }
1679  if(SYS_MASK & CPU_MASK)
1680  {
1681  fprintf(fp, "Idle%\t");
1682  }
1683  if(SYS_MASK & FDCOUNT_MASK)
1684  {
1685  fprintf(fp, "FDCountSystem\t");
1686  }
1687  if(SYS_MASK & CLICOUNT_MASK)
1688  {
1689  fprintf(fp, "ClientCount\t");
1690  }
1691  fprintf(fp, "\n");
1692  }
1693  else
1694  {
1695  fprintf(fp, "TimeStamp\t\tLoadAvg\tUsedMem\tIdle%\tFDCountSystem\tClientCount\n");
1696  }
1697 
1698  firstIter = false;
1699  }
1700 
1701  if(SYS_MASK)
1702  {
1703  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Start printing values to loadandmem file\n");
1704  fprintf(fp, "%s", GetCurTimeStamp());
1705  if(SYS_MASK & LOADAVG_MASK)
1706  {
1707  fprintf(fp, "\t%0.2f", loadAvg);
1708  }
1709  if(SYS_MASK & MEMORY_MASK)
1710  {
1711  fprintf(fp, "\t%ld", usedMemory);
1712  }
1713  if(SYS_MASK & CPU_MASK)
1714  {
1715  fprintf(fp, "\t%0.2f", idlePercent);
1716  }
1717  if(SYS_MASK & FDCOUNT_MASK)
1718  {
1719  fprintf(fp, "\t%d", FDCountSystem);
1720  }
1721  if(SYS_MASK & CLICOUNT_MASK)
1722  {
1723  fprintf(fp, "\t\t%d", cliCount);
1724  }
1725  fprintf(fp, "\n");
1726  }
1727  else
1728  {
1729  fprintf(fp, "%s\t%0.2f\t%ld\t%0.2f\t%d\t\t%d\n", GetCurTimeStamp(),
1730  loadAvg, usedMemory, idlePercent, FDCountSystem, cliCount);
1731  }
1732  fclose(fp);
1733  }
1734  else
1735  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d):ERROR opening loadandmem.data file\n", __func__, __LINE__);
1736  }
1737 
1738  if(monitorAllProcess == true)
1739  {
1740  char tstr[100];
1741  memset (tstr, 0, sizeof(tstr));
1742  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER","Monitoring all process...\n");
1743  sprintf (tstr, "ps -w > %s", ps_filename.c_str());
1744  if (system(tstr) == -1)
1745  {
1746  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): FAILED ps command\n", __func__, __LINE__);
1747  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Monitoring at system level only...\n", __func__, __LINE__);
1748  continue;
1749  }
1750  }
1751  else if(access(PROCESSES_LIST_PATH, F_OK) != -1)
1752  {
1753  FILE* ptr1=fopen(ps_filename.c_str(), "w");
1754 
1755  if (ptr1)
1756  {
1757  //Read from /opt/processes.list or /nvram/processes.list
1758  FILE* fp;
1759  fp = fopen(PROCESSES_LIST_PATH, "r");
1760  if (fp)
1761  {
1762  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Read from process list and populate Selected ps file\n");
1763  memset(buf1,0,64);
1764  memset(buf2,0,64);
1765  while (fgets(buf1,64,fp)!= NULL)
1766  {
1767  sprintf(tmpstring1,"pidof %s",buf1);
1768  FILE *ptr2 = popen(tmpstring1,"r");
1769  if (ptr2)
1770  {
1771  while (fscanf(ptr2,"%s",buf2) != EOF)
1772  {
1773  fprintf(ptr1,"%s\n",buf2);
1774  memset(buf2,0,64);
1775  }
1776  pclose(ptr2);
1777  } else {
1778  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Popen failure for process, %s\n", __func__, __LINE__, buf1);
1779  }
1780  memset(buf1,0,64);
1781  }
1782  fclose (fp);
1783  } else {
1784  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Process file open failure\n", __func__, __LINE__);
1785  }
1786  fclose(ptr1);
1787  }
1788  else
1789  {
1790  if(telemetryOnly == false)
1791  {
1792  RDK_LOG(RDK_LOG_ERROR,"LOG.RDK.CPUPROCANALYZER"," Error opening the file: %s",ps_filename.c_str());
1793  continue;
1794  }
1795  }
1796  }
1797  else
1798  {
1799  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER", "%s(%d): Monitoring at system level only...\n", __func__, __LINE__);
1800  monitorSysLevel = true;
1801  }
1802 
1803  if(!monitorSysLevel)
1804  {
1805  fp_selectedps = fopen(ps_filename.c_str(), "r");
1806  if(fp_selectedps)
1807  {
1808  while(!feof(fp_selectedps))
1809  {
1810  fgets(tmp_string, LINE_LIMIT, fp_selectedps);
1811  if(ferror(fp_selectedps) || feof(fp_selectedps))
1812  break;
1813  sscanf(tmp_string, "%d", &procData.d_pid);
1814  pthread_mutex_lock(&mtx);
1815  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Calling LogProcData\n");
1816  if(!LogProcData(&procData,0,"",0,telemetryOnly))
1817  {
1818  pthread_mutex_unlock(&mtx);
1819  continue;
1820  }
1821  pCount++;
1822  pthread_mutex_unlock(&mtx);
1823  if(telemetryOnly == false)
1824  {
1825  sprintf(tmp_string, "ls /proc/%d/task/ > %s%d_%s/threads.list", procData.d_pid, outputDir.c_str(), procData.d_pid, procData.s_comm);
1826  system(tmp_string);
1827  sprintf(tmp_string, "%s%d_%s/threads.list", outputDir.c_str(), procData.d_pid, procData.s_comm);
1828  FILE* fp_thread_list = fopen(tmp_string, "r");
1829  if(fp_thread_list)
1830  {
1831  while(!feof(fp_thread_list))
1832  {
1833  fgets(tmp_string, LINE_LIMIT, fp_thread_list);
1834  if( ferror(fp_thread_list) || feof(fp_thread_list) )
1835  break;
1836  sscanf(tmp_string, "%d", &threadData.d_pid);
1837  if(threadData.d_pid != procData.d_pid)
1838  {
1839  pthread_mutex_lock(&mtx);
1840  LogProcData(&threadData, procData.d_pid, procData.s_comm);
1841  pthread_mutex_unlock(&mtx);
1842  }
1843  }
1844  fclose(fp_thread_list);
1845  }
1846  memset(tmp_string,0,sizeof(tmp_string));
1847  }
1848  }
1849  fclose(fp_selectedps);
1850  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","MAP erase logic\n");
1851  map<unsigned int, struct stPrevData>::iterator it = prevData.begin();
1852  while(it != prevData.end())
1853  {
1854  stPrevData preData = it->second;
1855  if(preData.status == 0)
1856  {
1857  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","%s(%d): ***Removing %d from map***\n", __func__, __LINE__, it->first);
1858  prevData.erase(it);
1859  }
1860  else
1861  preData.status = 0;
1862  ++it;
1863  }
1864  }
1865  else
1866  {
1867  if(telemetryOnly == false)
1868  {
1869  RDK_LOG(RDK_LOG_ERROR, "LOG.RDK.CPUPROCANALYZER","%s(%d): ERROR opening the file: %s\n", __func__, __LINE__, ps_filename.c_str());
1870  }
1871  }
1872 
1873  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER", "[%d]No. of process monitored : %d\n\n", iteration, pCount);
1874  pCount = 0;
1875  }
1876 
1877  if(timeToRun_sec)
1878  {
1879  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Check time to run...\n");
1880  currentTime_sec = time(NULL);
1881  timeElapsed_sec = difftime(currentTime_sec, startTime_sec);
1882  if(timeElapsed_sec >= timeToRun_sec)
1883  {
1884  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Time elapsed, Terminate = true\n");
1885  terminate = true;
1886  }
1887  }
1888 
1889  if(!terminate)
1890  {
1891  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","Terminate NOT TRUE, sleep\n");
1892  usleep(sleepInterval_ms*1000);
1893  totalTimeElapsed_sec += sleepInterval_ms/1000;
1894  }
1895  }
1896 
1897  #if defined PROCANALYZER_BROADBAND
1898  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER", "Triggering RunCPUProcAnalyzer.sh stop...\n");
1899  if (telemetryOnly == false)
1900  {
1901  system("/lib/rdk/RunCPUProcAnalyzer.sh stop 1");
1902  }
1903  else
1904  {
1905  system("/lib/rdk/RunCPUProcAnalyzer.sh stop 0");
1906  }
1907 
1908  #elif defined PROCANALYZER_EXTENDER
1909  RDK_LOG(RDK_LOG_INFO,"LOG.RDK.CPUPROCANALYZER", "Stop CPU Proc Analyzer ...\n");
1910  system("/usr/opensync/scripts/run_procanalyzer.sh stop");
1911  #endif
1912 
1913  sleep(5);
1914  RDK_LOG(RDK_LOG_INFO, "LOG.RDK.CPUPROCANALYZER","%s(%d): ***Exiting the application***\n", __func__, __LINE__);
1915  return 0;
1916 }
1917 
1918 #ifndef PROCANALYZER_EXTENDER
1919 const char *rdk_logger_module_fetch(void)
1920 {
1921  return "LOG.RDK.CPUPROCANALYZER";
1922 }
1923 #endif
1924 /**
1925  * @} // End of Doxygen
1926  */
1927 
stProcData::ReadProcStat
void ReadProcStat(FILE *fp_procStat)
This function reads status of the Process and gives information like :
Definition: cpuproc_analyzer.cpp:532
GetUsedMemory
void GetUsedMemory(unsigned long *mem)
This function gives information about Used memory.
Definition: cpuproc_analyzer.cpp:715
GetIdlePercent
void GetIdlePercent(float *idlePercent)
This function gives the Idle percent value.
Definition: cpuproc_analyzer.cpp:765
stProcData::OutFilename
void OutFilename(char *outProcFilename, int ppid, char *pname)
This function constructs a file name based on parameters such as - output Directory Name,...
Definition: cpuproc_analyzer.cpp:569
ReadSkippingRandomChar
void ReadSkippingRandomChar(FILE *fp, char *str)
This function reads the Process Command Line Output from /proc/cmdline and removes extra characters.
Definition: cpuproc_analyzer.cpp:312
GetFDCountSystem
void GetFDCountSystem(int *FDCountSystem)
This function gives information about the File Descriptors at system level.
Definition: cpuproc_analyzer.cpp:839
SLEEP_SECS
#define SLEEP_SECS
Sleep Interval for the data collection.
Definition: cpuproc_analyzer.cpp:85
SetMask
uint SetMask(char *res)
This is to set the bit mask for System/Process.
Definition: cpuproc_analyzer.cpp:861
rdk_logger_module_fetch
const char * rdk_logger_module_fetch(void)
initialize logging Module
Definition: libpd.cpp:287
rdk_debug.h
EnvVarNode
Definition: rdk_logger_util.c:46
stProcData
Holds status of Process data such as :
Definition: cpuproc_analyzer.cpp:499
ReadProcessName
void ReadProcessName(FILE *fp, char *procName)
This function reads the Process Name from /proc/stat.
Definition: cpuproc_analyzer.cpp:287
stProcData::GetTotalUsedTime
void GetTotalUsedTime(unsigned long *outTotalTime)
This function gives Total CPU used time.
Definition: cpuproc_analyzer.cpp:581
GetCurTimeStamp
char * GetCurTimeStamp()
This function gives Current Date and Time in the format Year-Month-Day and Hours-Minutes-Seconds.
Definition: cpuproc_analyzer.cpp:628
LogProcData
int LogProcData(stProcData *procData, int ppid=0, char *pname="", int is_dynamic=0, bool telemetryOnly=0)
This function gives status information about the process.
Definition: cpuproc_analyzer.cpp:923
LINE_LIMIT
#define LINE_LIMIT
FILE LINE LIMIT.
Definition: cpuproc_analyzer.cpp:83
RDK_LOG
#define RDK_LOG
Definition: rdk_debug.h:258
stProcData::OutFilename
void OutFilename(char *outProcFilename, int is_dynamic)
This function constructs a file name based on parameters such as - output Directory Name,...
Definition: cpuproc_analyzer.cpp:549
GetLoadAverage
void GetLoadAverage(float *loadavg)
This function gives Load Average values.
Definition: cpuproc_analyzer.cpp:692
GetFDCount
void GetFDCount(char *filename, int *FDCount)
This function gives information about the File Descriptors in process.
Definition: cpuproc_analyzer.cpp:817
TIME_TO_RUN_SECS
#define TIME_TO_RUN_SECS
0 means, tool should run until it is killed manually
Definition: cpuproc_analyzer.cpp:86
main
int main(int argc, char **argv)
Main Function.
Definition: cpuproc_analyzer.cpp:1471
stCPUInfo
Holds status of CPU information such as Total Time and Idle Time of CPU.
Definition: cpuproc_analyzer.cpp:150
stPrevData
Holds status of previous data such as Total Major Faults Raised,Total CPU Used Time,...
Definition: cpuproc_analyzer.cpp:135
CreateExclusionList
void CreateExclusionList()
This function to exclude the process list of least concern.
Definition: cpuproc_analyzer.cpp:789
stProcData::GetSystemUsedTime
void GetSystemUsedTime(unsigned long *outSystemTime)
This function gives information about System used CPU time.
Definition: cpuproc_analyzer.cpp:605
rdk_logger_init
rdk_Error rdk_logger_init(const char *debugConfigFile)
Initialize the logger. Sets up the environment variable storage by parsing debug configuration file t...
Definition: rdk_logger_init.c:57
ReadDeviceName
void ReadDeviceName()
This function retrieves device name and manufacturer name.
Definition: cpuproc_analyzer.cpp:429
stProcData::GetUserUsedTime
void GetUserUsedTime(unsigned long *outUserTime)
This function gives User used CPU time.
Definition: cpuproc_analyzer.cpp:593
GetValuesFromFile
char * GetValuesFromFile(char *fname, char *searchStr, char *strValue, unsigned int strValueLen)
This function retrieves value of matching string from a file.
Definition: cpuproc_analyzer.cpp:331
GetMemParams
void GetMemParams(char *filename, unsigned long *memParam, char *param)
This function gives information about the Memory parameters.
Definition: cpuproc_analyzer.cpp:649
stProcData::GetTotalMjrFlts
void GetTotalMjrFlts(unsigned int *outTotalMjrFlts)
This function gives the information about Total Major Faults.
Definition: cpuproc_analyzer.cpp:617