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