1 /*****************************************************************************//***
2 * Copyright(c) <2017>, AT&T Intellectual Property. All other rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement: This product includes
14 * software developed by the AT&T.
15 * 4. Neither the name of AT&T nor the names of its contributors may be used to
16 * endorse or promote products derived from this software without specific
17 * prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *****************************************************************************/
40 #include <sys/types.h>
43 #include "afx_ves_reporter.h"
45 unsigned long long epoch_start = 0;
46 #define MAX_CHILDREN 100
49 /**************************************************************************//**
50 * Utility to compare linknames for ordering
51 *****************************************************************************/
52 int cmpfunc (const void * a, const void * b)
54 VPP_METRICS_STRUCT *aptr = (VPP_METRICS_STRUCT *)a;
55 VPP_METRICS_STRUCT *bptr = (VPP_METRICS_STRUCT *)b;
56 return ( strcmp(aptr->linkname,bptr->linkname) );
61 /**************************************************************************//**
62 * Gets CPU Load Statistics
64 * @param measurement Pointer to measurement event
67 *****************************************************************************/
68 void evel_get_cpu_stats(EVENT_MEASUREMENT * measurement)
87 MEASUREMENT_CPU_USE *cpu_use = NULL;
89 /* Open the command for reading. */
90 fp = popen("/usr/bin/mpstat -P ALL ", "r");
92 EVEL_ERROR(" AFX: Perf thread Failed to run command\n" );
96 /* Read the output a line at a time - output it. */
97 while (fgets(path, sizeof(path)-1, fp) != NULL) {
101 p = strtok (path, " ");
102 /* split string and append tokens to 'res' */
105 res = realloc (res, sizeof (char*) * ++n_spaces);
108 exit (-1); /* memory allocation failed */
112 p = strtok (NULL, " ");
115 /* realloc one extra element for the last NULL */
116 res = realloc (res, sizeof (char*) * (n_spaces+1));
119 /* print the result */
120 if( n_spaces > 2 && (!strcmp(res[2],"all") || isdigit(res[2][0])) )
122 //for (i = 0; i < (n_spaces+1); ++i)
124 // printf ("res[%d] = %s\n", i, res[i]);
126 if(isdigit(res[2][0]))
128 sprintf (cpname,"cpu%s", res[2]);
131 sprintf (cpname,"%s", res[2]);
136 idle = atof(res[12]);
137 usage = 100.0 - idle;
139 //allocate CPU stats structure
140 cpu_use = evel_measurement_new_cpu_use_add(measurement, cpname, usage);
141 if( cpu_use != NULL ){
142 evel_measurement_cpu_use_idle_set(cpu_use,idle);
143 //evel_measurement_cpu_use_interrupt_set(cpu_use,intrpt);
144 evel_measurement_cpu_use_nice_set(cpu_use,nice);
145 //evel_measurement_cpu_use_softirq_set(cpu_use,softirq);
146 //evel_measurement_cpu_use_steal_set(cpu_use,steal);
147 evel_measurement_cpu_use_system_set(cpu_use,sys);
148 evel_measurement_cpu_use_usageuser_set(cpu_use,usrl);
149 //evel_measurement_cpu_use_wait_set(cpu_use,wait);
155 /* free the memory allocated */
156 if(res != NULL) free (res);
164 /**************************************************************************//**
165 * tap live memory stats
166 *****************************************************************************/
167 void evel_get_mem_stats(EVENT_MEASUREMENT * measurement)
172 int bcount=0,lcount=0;
174 double membuffsz=0.0;
176 double memconfig=0.0;
180 double slabunrecl=0.0;
182 MEASUREMENT_MEM_USE *mem_use = NULL;
185 FILE * filp = fopen("/proc/meminfo", "rb");
186 int bytes_read = fread(buffer, sizeof(char), 4096, filp);
189 EVEL_INFO("AFX perfmon meminfo %d\n",bytes_read);
191 while ( bcount < bytes_read )
193 for(lcount=0; buffer[bcount] != '\n';bcount++,lcount++)
195 line[lcount] = buffer[bcount];
200 //printf("%s\n",line);
201 if(!strncmp(line,"Buffers:", strlen("Buffers:")))
203 sscanf(line+strlen("Buffers:"),"%lf",&membuffsz);
204 //printf("membuff %lf\n",membuffsz);
206 else if(!strncmp(line,"Cached:", strlen("Cached:")))
208 sscanf(line+strlen("Cached:"),"%lf",&memcache);
210 else if(!strncmp(line,"MemTotal:", strlen("MemTotal:")))
212 sscanf(line+strlen("MemTotal:"),"%lf",&memconfig);
214 else if(!strncmp(line,"MemFree:", strlen("MemFree:")))
216 sscanf(line+strlen("MemFree:"),"%lf",&memfree);
218 else if(!strncmp(line,"Slab:", strlen("Slab:")))
220 sscanf(line+strlen("Slab:"),"%lf",&slab);
222 else if(!strncmp(line,"SReclaimable:", strlen("SReclaimable:")))
224 sscanf(line+strlen("SReclaimable:"),"%lf",&slabrecl);
226 else if(!strncmp(line,"SUnreclaim:", strlen("SUnreclaim:")))
228 sscanf(line+strlen("SUnreclaim:"),"%lf",&slabunrecl);
234 memused = memconfig - memfree - membuffsz - memcache - slab;
235 EVEL_INFO(" AFX perfmon memused %lf\n",memused);
237 mem_use = evel_measurement_new_mem_use_add(measurement, "RAM", hostname, membuffsz);
238 evel_measurement_mem_use_memcache_set(mem_use,memcache);
239 evel_measurement_mem_use_memconfig_set(mem_use,memconfig);
240 evel_measurement_mem_use_memfree_set(mem_use,memfree);
241 evel_measurement_mem_use_slab_reclaimed_set(mem_use,slabrecl);
242 evel_measurement_mem_use_slab_unreclaimable_set(mem_use,slabunrecl);
243 evel_measurement_mem_use_usedup_set(mem_use,memused);
248 * System command execution output
249 * @param <char> command - system command to execute
250 * @returb <char> execution output
252 char *system_output (const char *command)
255 static char out[512];
257 pipe = popen (command, "r");
260 fgets (out, sizeof(out), pipe);
268 * Finding all process's children
269 * @param <Int> - process ID
270 * @param <Int> - array of childs
272 void find_children (int pid, int children[])
274 int child_pid, i = 1;
275 char empty_command[] = "/bin/ps h -o pid --ppid ";
278 snprintf(pid_string, 5, "%d", pid);
280 char *command = (char*) malloc(strlen(empty_command) + strlen(pid_string) + 1);
281 sprintf(command, "%s%s", empty_command, pid_string);
283 FILE *fp = popen(command, "r");
286 while (fscanf(fp, "%i", &child_pid) != EOF)
288 children[i] = child_pid;
298 * Parsign `ps` command output
299 * @param <char> out - ps command output
300 * @return <int> cpu utilization
302 int parse_cpu_utilization (char *out, float *pcpu, float *pmem)
304 if( strlen(out) > 0 )
306 sscanf (out, "%f %f", pcpu, pmem);
312 void gather_afx_stats(EVENT_MEASUREMENT *vpp_m,char *lkstr)
314 double totcpu=0.0,totmem=0.0;
315 float tmpcpu=0.0,tmpmem=0.0;
323 //unsigned pid = atoi(argv[1]);
325 // getting array with process children
326 int process_children[MAX_CHILDREN] = { 0 };
328 float common_cpu_usage = 0.0;
330 /* Open the command for reading. */
331 sprintf(cmd," pgrep -f \"%s\" | xargs --no-run-if-empty ps --no-headers ", lkstr);
332 fp = popen(cmd, "r");
334 EVEL_ERROR("AFX meas : Failed to run afx command\n" );
338 /* Read the output a line at a time - output it. */
339 while ( !feof(fp) ) {
340 while (fgets(path, sizeof(path)-1, fp) != NULL) {
341 EVEL_DEBUG("AFX meas : %s",path);
343 while( p!=NULL && isspace(*p))p++;
344 if( strstr(p,"sh -c") == NULL && isdigit(*p))
346 sscanf(p,"%d ",&pid);
347 //printf(":%d:\n",pid);
348 process_children[0] = pid; // parent PID as first element
349 find_children(pid, process_children);
351 // calculating summary processor utilization
352 for (i = 0; i < sizeof(process_children)/sizeof(int); ++i)
354 if (process_children[i] > 0)
356 char *command = (char*)malloc(128);
357 EVEL_DEBUG ("AFX meas :/bin/ps -p %i -o 'pcpu,pmem' --no-headers\n", process_children[i]);
358 sprintf (command, "/bin/ps -p %i -o 'pcpu,pmem' --no-headers", process_children[i]);
359 parse_cpu_utilization(system_output(command),&tmpcpu,&tmpmem);
364 sprintf(grp,"%s_%d",lkstr,pid);
365 EVEL_DEBUG("%s %d CPU %f MEM %f\n", grp, totcpu, totmem);
366 sprintf(cpustr,"%f",totcpu);
367 sprintf(memstr,"%f",totmem);
368 evel_measurement_custom_measurement_add(vpp_m,grp,"cpu",cpustr);
369 evel_measurement_custom_measurement_add(vpp_m,grp,"mem",memstr);
381 /**************************************************************************//**
383 *****************************************************************************/
384 void evel_get_afx_stats(EVENT_MEASUREMENT * measurement)
386 gather_afx_stats(measurement,"AFXin");
387 gather_afx_stats(measurement,"AFXout");
390 /**************************************************************************//**
391 * Thread function to Monitor AFX Performance parameters
392 * Opens interface list file to get list of interfaces
393 * Opens Device driver file every READ_INTERVAL and calculates
394 * Delta packets and bytes
396 * @param threadarg Thread arguments for startup message
399 *****************************************************************************/
400 void *MeasureAfxThread(void *threadarg)
402 struct thread_data *my_data;
405 struct timeval time_val;
407 //time_t start_epoch;
409 EVEL_ERR_CODES evel_rc = EVEL_SUCCESS;
410 EVENT_MEASUREMENT* vpp_m = NULL;
411 EVENT_HEADER* vpp_m_header = NULL;
412 MEASUREMENT_VNIC_PERFORMANCE * vnic_performance = NULL;
413 //struct timeval tv_start;
415 char const* const fileName = AFX_INTERFACE_FILE;
428 VPP_METRICS_STRUCT intfstats[MAX_INTERFACES];
429 VPP_METRICS_STRUCT *ptritem;
430 uint64_t curr_rx_bytes;
431 uint64_t curr_rx_packets;
432 uint64_t curr_rx_mcast;
433 uint64_t curr_tx_bytes;
434 uint64_t curr_tx_packets;
439 my_data = (struct thread_data *) threadarg;
440 taskid = my_data->thread_id;
442 hello_msg = my_data->message;
443 EVEL_INFO("AFX Perf Thread %d: %s Sum=%d\n", taskid, hello_msg, sum);
444 sprintf(vesevid,"measurementsForVfScaling_vAfx_%s",get_oam_intfaddr());
446 gettimeofday(&time_val, NULL);
447 epoch_start = time_val.tv_sec * 1000000 + time_val.tv_usec;
448 sleep(PERF_MONITOR_INTERVAL);
452 if( file_is_modified(fileName, &filetime) ) newrun = 1;
457 FILE* file = fopen(fileName, "r"); /* should check the result */
459 while ( file != NULL && fgets(line, sizeof(line), file)) {
460 /* note that fgets don't strip the terminating \n, checking its
461 presence would allow to handle lines longer that sizeof(line) */
462 //printf("%s", line);
463 sscanf(line,"%s %s",intf,descr);
464 //remove_spaces(line);
465 if ((pos=strchr(line, '\n')) != NULL)
468 memset(&intfstats[linkcount],0,sizeof(VPP_METRICS_STRUCT));
469 strcpy(intfstats[linkcount].linkname,intf);
470 strcpy(intfstats[linkcount].linkdescr,line);
475 if ((pos=strchr(line, '\n')) != NULL)
477 qsort(intfstats,linkcount,sizeof(VPP_METRICS_STRUCT),cmpfunc);
481 /* Open the command for reading. */
482 fp = popen("cat /proc/net/dev ", "r");
484 EVEL_DEBUG("Failed to run net command\n" );
486 sleep(PERF_MONITOR_INTERVAL);
490 /* Read the output a line at a time - output it. */
491 while ( !feof(fp) ) {
492 while (fgets(linkdata, sizeof(linkdata)-1, fp) != NULL) {
493 //printf("%s",linkdata);
496 p = strtok (linkdata, " ");
497 /* split string and append tokens to 'res' */
500 res = realloc (res, sizeof (char*) * ++n_spaces);
503 EVEL_DEBUG("Memory allocation failed");
504 exit (-1); /* memory allocation failed */
509 p = strtok (NULL, " ");
512 /* realloc one extra element for the last NULL */
513 res = realloc (res, sizeof (char*) * (n_spaces+1));
517 if( !strstr(res[0],"Inter") && !strstr(res[0],"face") )
519 /* for (i = 0; i < (n_spaces+1); ++i)
521 printf ("res[%d] = %s\n", i, res[i]);
523 if ((pos=strchr(res[0], ':')) != NULL)
525 /* using bsearch() to find value 32 in the array */
526 ptritem = (VPP_METRICS_STRUCT*) bsearch (res[0], intfstats, linkcount, sizeof(VPP_METRICS_STRUCT), cmpfunc);
527 if( ptritem == NULL )
529 EVEL_DEBUG("Item = %s could not be found\n", res[0]);
531 else if( !strcmp(res[0],ptritem->linkname) )
533 EVEL_DEBUG( "AFX Perf values Link %d rxb %d rxp %d rxm %d txb %d txp %d\n", linkcount, ptritem->rx_bytes, ptritem->rx_packets, ptritem->rx_mcast, ptritem->tx_bytes, ptritem->tx_packets );
535 curr_rx_bytes = strtoull(res[1],NULL,10);
536 curr_rx_packets = strtoull(res[2],NULL,10);
537 curr_rx_mcast = strtoull(res[8],NULL,10);
538 curr_tx_bytes = strtoull(res[9],NULL,10);
539 curr_tx_packets = strtoull(res[10],NULL,10);
541 ptritem->delta_rx_bytes = curr_rx_bytes - ptritem->rx_bytes;
542 ptritem->delta_rx_packets = curr_rx_packets - ptritem->rx_packets;
543 ptritem->delta_rx_mcast = curr_rx_mcast - ptritem->rx_mcast;
544 ptritem->delta_tx_bytes = curr_tx_bytes - ptritem->tx_bytes;
545 ptritem->delta_tx_packets = curr_tx_packets - ptritem->tx_packets;
549 ptritem->delta_rx_bytes = 0;
550 ptritem->delta_rx_packets = 0;
551 ptritem->delta_rx_mcast = 0;
552 ptritem->delta_tx_bytes = 0;
553 ptritem->delta_tx_packets = 0;
555 ptritem->rx_bytes = curr_rx_bytes;
556 ptritem->rx_packets = curr_rx_packets;
557 ptritem->rx_mcast = curr_rx_mcast;
558 ptritem->tx_bytes = curr_tx_bytes;
559 ptritem->tx_packets = curr_tx_packets;
561 //printf( "Acc %s %d %d %d %d %d\n", ptritem->linkname, curr_rx_bytes, curr_rx_packets, curr_rx_mcast, curr_tx_bytes, curr_tx_packets );
562 //printf( "Delta %d %d %d %d %d\n", ptritem->delta_rx_bytes, ptritem->delta_rx_packets, ptritem->delta_rx_mcast, ptritem->delta_tx_bytes, ptritem->delta_tx_packets );
570 if(res != NULL) free (res);
573 /***************************************************************************/
574 /* Collect metrics from the VNIC */
575 /***************************************************************************/
576 vpp_m = evel_new_measurement(PERF_MONITOR_INTERVAL,"measurementsForVfScaling_vAfx",vesevid);
579 evel_header_type_set((EVENT_HEADER *)vpp_m, "applicationVnf");
580 evel_nfcnamingcode_set((EVENT_HEADER *)vpp_m, "AFX");
581 evel_nfnamingcode_set((EVENT_HEADER *)vpp_m, "AFX");
582 EVEL_DEBUG("New measurement report created...\n");
584 for( i=0; i<linkcount;i++)
586 ptritem = &intfstats[i];
587 vnic_performance = (MEASUREMENT_VNIC_PERFORMANCE *)evel_measurement_new_vnic_performance
588 (ptritem->linkdescr, "true");
590 evel_meas_vnic_performance_add(vpp_m, vnic_performance);
592 //printf( "Acc %s %d %d %d %d %d\n", ptritem->linkname, curr_rx_bytes, curr_rx_packets, curr_rx_mcast, curr_tx_bytes, curr_tx_packets );
593 //printf( "Delta %d %d %d %d %d\n", delta_rx_bytes, delta_rx_packets, delta_rx_mcast, delta_tx_bytes, delta_tx_packets );
594 evel_vnic_performance_rx_octets_acc_set(vnic_performance, ptritem->rx_bytes);
595 evel_vnic_performance_rx_octets_delta_set(vnic_performance, ptritem->delta_rx_bytes);
596 evel_vnic_performance_tx_octets_acc_set(vnic_performance, ptritem->tx_bytes);
597 evel_vnic_performance_tx_octets_delta_set(vnic_performance, ptritem->delta_tx_bytes);
599 evel_vnic_performance_rx_mcast_pkt_acc_set(vnic_performance, ptritem->rx_mcast);
600 evel_vnic_performance_rx_mcast_pkt_delta_set(vnic_performance, ptritem->delta_rx_mcast);
602 evel_vnic_performance_rx_total_pkt_acc_set(vnic_performance, ptritem->rx_packets);
603 evel_vnic_performance_rx_total_pkt_delta_set(vnic_performance, ptritem->delta_rx_packets);
604 evel_vnic_performance_tx_total_pkt_acc_set(vnic_performance, ptritem->tx_packets);
605 evel_vnic_performance_tx_total_pkt_delta_set(vnic_performance, ptritem->delta_tx_packets);
609 evel_get_cpu_stats(vpp_m);
610 evel_get_mem_stats(vpp_m);
611 evel_get_afx_stats(vpp_m);
612 /***************************************************************************/
613 /* Set parameters in the MEASUREMENT header packet */
614 /***************************************************************************/
615 struct timeval tv_now;
616 gettimeofday(&tv_now, NULL);
617 unsigned long long epoch_now = tv_now.tv_usec + 1000000 * tv_now.tv_sec;
619 //last_epoch = start_epoch + PERF_MONITOR_INTERVAL * 1000000;
620 vpp_m_header = (EVENT_HEADER *)vpp_m;
621 evel_start_epoch_set(&vpp_m->header, epoch_start);
622 evel_last_epoch_set(&vpp_m->header, epoch_now);
623 epoch_start = epoch_now;
625 evel_reporting_entity_name_set(&vpp_m->header, "AFXM");
626 evel_reporting_entity_id_set(&vpp_m->header, hostname);
627 evel_rc = evel_post_event(vpp_m_header);
629 if(evel_rc == EVEL_SUCCESS) {
630 EVEL_DEBUG("Measurement report correctly sent to the collector!\n");
633 EVEL_DEBUG("Post failed %d (%s)\n", evel_rc, evel_error_string());
637 EVEL_DEBUG("New measurement report failed (%s)\n", evel_error_string());
640 sleep(PERF_MONITOR_INTERVAL);
643 /***************************************************************************/
645 /***************************************************************************/