1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdarg.h> 18#include <time.h> 19#include "dmStringUtil.h" 20#include "dmprofile.h" 21#include "dmThreadHelper.h" 22#include "dmstring.h" 23 24#ifdef DM_FILE_OUTPUT 25 26void DMFileOutput( const char* szFormat, ... ) 27{ 28 static int s_nFirstCall = 1; // mark first access to write some additional info 29 static char filename[255]; 30 31 FILE * fp=NULL; 32 33 if ( s_nFirstCall ){ 34 s_nFirstCall = 0; 35 36 const char* dm_settings_env = getenv("dm_setting_root"); 37 38 if ( !dm_settings_env ) 39 dm_settings_env = ""; 40 41 DmStrcpy (filename, dm_settings_env); 42 DmStrcat( filename, "/a/motorola/settings/DMOUTPUT.txt" ); 43 44 fp=fopen(filename, "a+"); 45 if (!fp) 46 return; 47 48 time_t elapstime; 49 time(&elapstime); 50 51 fprintf(fp, "\nLog started at %s \n", 52 ctime(&elapstime)); 53 fclose(fp); 54 fp=NULL; 55 } 56 57 fp=fopen(filename, "a+"); 58 if (!fp) 59 return; 60 61 va_list ap; 62 va_start(ap, szFormat); 63 vfprintf( fp, szFormat, ap ); 64 va_end(ap); 65 66 fclose(fp); 67 fp=NULL; 68} 69 70#endif 71 72#ifdef DM_PROFILER_ENABLED 73 74#include <sys/types.h> 75#include <sys/stat.h> 76#include <fcntl.h> 77 78CDMProfCell g_aProfStorage[PROF_CELL_NUM]; 79int g_nProfCurCell = 0; 80 81class CProfileCmdListener : public DMThread{ 82public: 83 CProfileCmdListener() { 84 StartThread(); 85 } 86 ~CProfileCmdListener() { 87 StopThread(); 88 } 89 90 enum { eNone, eError, eReset, ePrint, ePrintPipe}; 91 virtual void* Run(); 92 int GetCommand( int nPipe ); 93 void PrintResult( int nFile ); 94 95 DMString _sOutPipe; 96}; 97 98#define PROF_CMD_PIPE_NAME "/tmp/dmprof" 99 100void* CProfileCmdListener::Run() 101{ 102printf("DM profile command listener is started\n" 103 "use file " PROF_CMD_PIPE_NAME " to manipulate it\n"); 104 105{ 106 // check for cvm 107 char szFile[1024]; 108 109 sprintf( szFile, "/proc/%d/cmdline", (int)getpid() ); 110 int nF = open( szFile, O_RDONLY ); 111 if ( nF >= 0 ){ 112 read( nF, szFile, sizeof(szFile ) ); 113 close (nF); 114 115 if ( strstr( szFile, "cvm") == NULL ) 116 return NULL; 117 } 118} 119 120 if (mkfifo(PROF_CMD_PIPE_NAME, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) 121 printf("Failed to create pipe\n"); 122 123 int nPipe = open(PROF_CMD_PIPE_NAME, O_NONBLOCK ); 124 125 if ( nPipe < 0 ){ 126 printf( "Failed to open pipe - cmd listener terminated\n"); 127 return 0; 128 } 129 130 while (m_bRunning) 131 { 132 int nCmd = GetCommand( nPipe ); 133 134 if ( nCmd != eNone ) 135 printf( "Cmd received %d\n\n\n", nCmd ); 136 137 //printf("Stat %d:\n", g_nProfCurCell); 138 139 switch ( nCmd ){ 140 case eReset: 141 printf("Reset\n"); 142 g_nProfCurCell = 0; 143 break; 144 145 case ePrint: 146 PrintResult(-1); 147 break; 148 149 case ePrintPipe: 150 { 151 int nFile = open( _sOutPipe, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP ); 152 PrintResult(nFile); 153 if ( nFile > -1 ) 154 close( nFile ); 155 } 156 break; 157 }; 158 } 159 160 close( nPipe ); 161 162 return 0; 163} 164 165int CProfileCmdListener::GetCommand( int nPipe ) 166{ 167 if ( nPipe < 0 | nPipe > 1023 ) 168 return -1; 169 170 int rc; 171 fd_set fds; 172 struct timeval tv; 173 174 FD_ZERO(&fds); 175 FD_SET(nPipe,&fds); 176 tv.tv_sec = 1; 177 tv.tv_usec = 0; 178 179 rc = select(nPipe+1, &fds, NULL, NULL, &tv); 180 if (rc < 0) 181 return eError; 182 183 if (!FD_ISSET(nPipe,&fds) ) 184 return eNone; 185 186 char szCmd[50] = ""; 187 188 int nBytes = read( nPipe, szCmd, sizeof(szCmd)); 189 190 if ( nBytes == 0 ){ 191 sleep(1); 192 return eNone; 193 } 194 195 if ( strncmp( szCmd, "reset", 5) == 0 ) 196 return eReset; 197 198 if ( strncmp( szCmd, "print", 5) == 0 ) 199 return ePrint; 200 201 if ( strncmp( szCmd, "out", 3) == 0 ){ 202 _sOutPipe.assign(szCmd + 4, nBytes - 4); 203 printf( "out to [%s]\n", _sOutPipe.c_str() ); 204 return ePrintPipe; 205 } 206 207 return eError; 208 209} 210 211void CProfileCmdListener::PrintResult( int nFile ) 212{ 213 int n = 0; 214 long long nTot = 0; 215 char szBuf[10096]; 216 217 while ( n < g_nProfCurCell ){ 218 219 if ( g_aProfStorage[n % PROF_CELL_NUM]._s ) { 220 int nLen = sprintf( szBuf, "%d: DMProfile: %s, time is %lld usec, from %lld to %lld\n", 221 n+1, 222 g_aProfStorage[n % PROF_CELL_NUM]._s, 223 g_aProfStorage[n % PROF_CELL_NUM]._elapsed, 224 g_aProfStorage[n % PROF_CELL_NUM]._from, 225 g_aProfStorage[n % PROF_CELL_NUM]._elapsed + g_aProfStorage[n % PROF_CELL_NUM]._from ); 226 227 if ( nFile >= 0 ) 228 write( nFile, szBuf, nLen ); 229 else 230 printf( "%s", szBuf ); 231 232 nTot += g_aProfStorage[n % PROF_CELL_NUM]._elapsed; 233 } 234 235 free( (void*)g_aProfStorage[n % PROF_CELL_NUM]._s ); 236 g_aProfStorage[n % PROF_CELL_NUM]._s = NULL; 237 n++; 238 } 239 240 int nLen = sprintf( szBuf, "Total time is %lld\n", nTot ); 241 if ( nFile >= 0 ) 242 write( nFile, szBuf, nLen ); 243 else 244 printf( "%s", szBuf ); 245 246 g_nProfCurCell = 0; 247} 248 249CProfileCmdListener g_oProfileCmdListener; 250 251#endif 252 253#ifdef DM_PROFILER_STACK 254 255#include <sys/types.h> 256#include <sys/stat.h> 257#include <fcntl.h> 258 259 260DMProfileData __aProfStackStorage[PROF_STACK_NUM]; 261 262int g_nProfCurCell = 0; 263 264 265class CProfileStackCmdListener : public DMThread{ 266public: 267 CProfileStackCmdListener() { 268 StartThread(); 269 } 270 ~CProfileStackCmdListener() { 271 StopThread(); 272 } 273 274 enum { eNone, eError, eReset, ePrint, ePrintPipe}; 275 virtual void* Run(); 276 int GetCommand( int nPipe ); 277 void PrintResult( int nFile ); 278 279 DMString _sOutPipe; 280}; 281 282#define PROF_CMD_PIPE_NAME "/tmp/dmprofstack" 283 284void* CProfileStackCmdListener::Run() 285{ 286 printf("DM profile STACK command listener is started\n" 287 "use file " PROF_CMD_PIPE_NAME " to manipulate it\n"); 288 289 { 290 // check for cvm 291 char szFile[1024]; 292 293 sprintf( szFile, "/proc/%d/cmdline", (int)getpid() ); 294 int nF = open( szFile, O_RDONLY ); 295 if ( nF >= 0 ){ 296 read( nF, szFile, sizeof(szFile ) ); 297 close (nF); 298 299 if ( strstr( szFile, "cvm") == NULL ) 300 return NULL; 301 } 302 } 303 304 if (mkfifo(PROF_CMD_PIPE_NAME, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) 305 printf("Failed to create pipe\n"); 306 307 int nPipe = open(PROF_CMD_PIPE_NAME, O_NONBLOCK ); 308 309 if ( nPipe < 0 ){ 310 printf( "Failed to open pipe - cmd listener terminated\n"); 311 return 0; 312 } 313 314 while (m_bRunning) 315 { 316 int nCmd = GetCommand( nPipe ); 317 318 if ( nCmd != eNone ) 319 printf( "Cmd received %d\n\n\n", nCmd ); 320 321 switch ( nCmd ){ 322 case eReset: 323 printf("Reset\n"); 324 g_nProfCurCell = 0; 325 break; 326 327 case ePrint: 328 PrintResult(-1); 329 break; 330 331 case ePrintPipe: 332 { 333 int nFile = open( _sOutPipe, O_WRONLY | O_CREAT | O_APPEND ); 334 PrintResult(nFile); 335 if ( nFile > -1 ) 336 close( nFile ); 337 } 338 break; 339 }; 340 } 341 342 close( nPipe ); 343 344 return 0; 345} 346 347int CProfileStackCmdListener::GetCommand( int nPipe ) 348{ 349 if ( nPipe < 0 | nPipe > 1023 ) 350 return -1; 351 352 int rc; 353 fd_set fds; 354 struct timeval tv; 355 356 FD_ZERO(&fds); 357 FD_SET(nPipe,&fds); 358 tv.tv_sec = 1; 359 tv.tv_usec = 0; 360 361 rc = select(nPipe+1, &fds, NULL, NULL, &tv); 362 if (rc < 0) 363 return eError; 364 365 if (!FD_ISSET(nPipe,&fds) ) 366 return eNone; 367 368 char szCmd[50] = ""; 369 370 int nBytes = read( nPipe, szCmd, sizeof(szCmd)); 371 372 if ( nBytes == 0 ){ 373 sleep(1); 374 return eNone; 375 } 376 377 if ( strncmp( szCmd, "reset", 5) == 0 ) 378 return eReset; 379 380 if ( strncmp( szCmd, "print", 5) == 0 ) 381 return ePrint; 382 383 if ( strncmp( szCmd, "out", 3) == 0 ){ 384 _sOutPipe.assign(szCmd + 4, nBytes - 4); 385 printf( "out to [%s]\n", _sOutPipe.c_str() ); 386 return ePrintPipe; 387 } 388 389 return eError; 390} 391 392void CProfileStackCmdListener::PrintResult( int nFile ) 393{ 394 int n = 0; 395 long long nTot = 0; 396 char szBuf[10096]; 397 398 int nLen = sprintf( szBuf, "<DMProfiles>\n"); 399 if ( nFile >= 0 ) 400 write( nFile, szBuf, nLen ); 401 else 402 printf( "%s", szBuf ); 403 404 while ( n < g_nProfCurCell ){ 405 406 if ( __aProfStackStorage[n % PROF_STACK_NUM]._elapsed ) { 407 408 nLen = sprintf( szBuf, " <DMProfile>\n"); 409 if ( nFile >= 0 ) 410 write( nFile, szBuf, nLen ); 411 else 412 printf( "%s", szBuf ); 413 414 nLen = sprintf( szBuf, " <ID>%d</ID>\n <ElapseTime>%lld</ElapseTime>\n <BeginTime>%lld</BeginTime>\n <EndTime>%lld</EndTime>\n%s", 415 n+1, 416 __aProfStackStorage[n % PROF_STACK_NUM]._elapsed, 417 __aProfStackStorage[n % PROF_STACK_NUM]._from, 418 __aProfStackStorage[n % PROF_STACK_NUM]._elapsed + __aProfStackStorage[n % PROF_STACK_NUM]._from, 419 __aProfStackStorage[n % PROF_STACK_NUM]._s); 420 421 if ( nFile >= 0 ) 422 write( nFile, szBuf, nLen ); 423 else 424 printf( "%s", szBuf ); 425 426 427 nLen = sprintf( szBuf, " </DMProfile>\n"); 428 if ( nFile >= 0 ) 429 write( nFile, szBuf, nLen ); 430 else 431 printf( "%s", szBuf ); 432 433 nTot += __aProfStackStorage[n % PROF_STACK_NUM]._elapsed; 434 } 435 436 free( (void*)__aProfStackStorage[n % PROF_STACK_NUM]._s ); 437 __aProfStackStorage[n % PROF_STACK_NUM]._s = NULL; 438 n++; 439 } 440 441 nLen = sprintf( szBuf, "</DMProfiles>\n"); 442 if ( nFile >= 0 ) 443 write( nFile, szBuf, nLen ); 444 else 445 printf( "%s", szBuf ); 446 447 g_nProfCurCell = 0; 448} 449 450CProfileStackCmdListener g_oProfileStackCmdListener; 451 452#endif 453