sysresmonitoring/oommonitor/src/oomlog.cpp
changeset 35 13fd6fd25fe7
child 46 eea20ed08f4b
equal deleted inserted replaced
29:6a787171e1de 35:13fd6fd25fe7
       
     1 /*
       
     2 * Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Logging functionality for OOM monitor profiling.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #ifdef _DEBUG
       
    21 
       
    22 #include <hal.h>
       
    23 #include <w32std.h>
       
    24 #include <e32std.h>
       
    25 #include <apgwgnam.h>
       
    26 #include <flogger.h>
       
    27 
       
    28 #include "oomlog.h"
       
    29 #include "oompanic.h"
       
    30 
       
    31 _LIT8(KMemorySampleLoggingString, "%d");
       
    32 _LIT8(KMemorySampleLoggingSeparator, ", ");
       
    33 
       
    34 _LIT8(KCrLf, "\r\n");
       
    35 
       
    36 _LIT8(KOomLogCancel, "Sampling triggered before previous sampling has completed. Results so far: ");
       
    37 
       
    38 _LIT(KOomLogFile, ":\\logs\\OOM\\liveoommonitor.txt");
       
    39 _LIT(KOomOldLogFile, ":\\logs\\OOM\\oommonitor.txt");
       
    40 
       
    41 const TInt KMaxTimeStampSize = 30;
       
    42 _LIT(KTimeStampFormat, "%F    %H:%T:%S");
       
    43 
       
    44 _LIT(KDummyWgName, "20");
       
    45 
       
    46 _LIT8(KUidPreamble, "App UIDs:");
       
    47 _LIT8(KUidFormat, " 0x%x");
       
    48 
       
    49 const TInt KPreallocatedSpaceForAppList = 50;
       
    50 
       
    51 const TInt KMaxUidBufferSize = 1024;
       
    52 
       
    53 COomLogger* COomLogger::NewL(RWsSession& aWs, RFs& aFs)
       
    54     {
       
    55     COomLogger* self = new (ELeave) COomLogger(aWs, aFs);
       
    56     CleanupStack::PushL(self);
       
    57     self->ConstructL();
       
    58     CleanupStack::Pop(self);
       
    59     return self;
       
    60     }
       
    61     
       
    62 // Start logging the available memory every n micro seconds
       
    63 // Firstly a list of the app IDs is written to the log (foreground app first)
       
    64 // Note that the log is created in memory (to a pre-allocated buffer) and flushed out after it is complete
       
    65 // the samples are saved in CSV format so that they can easily be cut and pasted to plot graphs etc.
       
    66 void COomLogger::StartL()
       
    67     {
       
    68     // If the log file doesn't exist then don't attempt to sample anything
       
    69     if (!iIsOpen)
       
    70         return;
       
    71     
       
    72     // If we are already active then cancel first
       
    73     if (IsActive())
       
    74         Cancel();
       
    75     
       
    76     iWriteBuffer.Zero();
       
    77     
       
    78     iStartTime.HomeTime();
       
    79     
       
    80     // Log the timestamp
       
    81     TBuf16<KMaxTimeStampSize> timeStamp;
       
    82     iStartTime.FormatL(timeStamp, KTimeStampFormat);
       
    83     TBuf8<KMaxTimeStampSize> timeStamp8;
       
    84     timeStamp8.Copy(timeStamp);
       
    85     Write(timeStamp8);
       
    86     
       
    87     // Log all of the application IDs (foreground app first, then the other apps moving towards the back)
       
    88     LogApplicationIds();
       
    89 
       
    90     // Then, record the free memory
       
    91     // Note that this is done to a buffer so as not to affect the timing too much
       
    92     LogFreeMemory();
       
    93     
       
    94     // Finally, set a timer to record the memory every n microseconds
       
    95     HighRes(KTimeBetweenMemorySamples);
       
    96     }
       
    97 
       
    98 // From CTimer / CActice
       
    99 void COomLogger::RunL()
       
   100     {
       
   101     TTime currentTime;
       
   102     currentTime.HomeTime();
       
   103     TTimeIntervalMicroSeconds loggingDuration = currentTime.MicroSecondsFrom(iStartTime);
       
   104     TTimeIntervalMicroSeconds samplingDuration = KSamplingDurationUint;
       
   105     if (loggingDuration > samplingDuration)
       
   106         // If we have passed the desired logging duration then write the data we have collected
       
   107         {
       
   108         Write(iWriteBuffer);
       
   109         }
       
   110     else
       
   111         {
       
   112         // If we haven't passed the desired logging duration then record the free memory
       
   113         // Note that this is recorded into a buffer and then logged later
       
   114         iWriteBuffer.Append(KMemorySampleLoggingSeparator);
       
   115         LogFreeMemory();
       
   116         
       
   117         // Wait before taking another memory sample
       
   118         HighRes(KTimeBetweenMemorySamples);
       
   119         }
       
   120     }
       
   121 
       
   122 void COomLogger::DoCancel()
       
   123     {
       
   124     CTimer::DoCancel();
       
   125     
       
   126     Write(KOomLogCancel);
       
   127     Write(iWriteBuffer);
       
   128     }
       
   129 
       
   130 COomLogger::~COomLogger()
       
   131     {
       
   132     iWgIds.Close();
       
   133  // delete iWgName; // Not owned
       
   134     if (iIsOpen)
       
   135         iFile.Close();
       
   136 
       
   137     }
       
   138 
       
   139 void COomLogger::Write(const TDesC8& aBuffer)
       
   140     {
       
   141     if (iIsOpen)
       
   142         {
       
   143         iFile.Write(aBuffer);
       
   144     
       
   145         // Add the line break
       
   146         iFile.Write(KCrLf);
       
   147         }
       
   148     }
       
   149 
       
   150 void COomLogger::LogApplicationIds()
       
   151     {
       
   152     // get all window groups, with info about parents
       
   153     TInt numGroups = iWs.NumWindowGroups(0);
       
   154     TRAPD(err, iWgIds.ReserveL(numGroups));
       
   155     
       
   156     if (err != KErrNone)
       
   157         return;
       
   158     
       
   159     if (iWs.WindowGroupList(0, &iWgIds) != KErrNone)
       
   160         return;
       
   161 
       
   162     // Remove all child window groups, promote parents to foremost child position
       
   163     ColapseWindowGroupTree();
       
   164     
       
   165     // Go through each window group ID in the list, get the Uid of each app then log it
       
   166     // Start with the foreground application
       
   167     TInt index = 0;
       
   168     
       
   169     TUid uid;
       
   170     
       
   171     TBuf8<KMaxUidBufferSize> uidBuffer;
       
   172     
       
   173     uidBuffer = KUidPreamble;
       
   174     
       
   175     while (index < numGroups)
       
   176         {
       
   177         __ASSERT_DEBUG(index < iWgIds.Count(), OomMonitorPanic(KWindowGroupArrayIndexOutOfBounds));    
       
   178         uid = GetUidFromWindowGroupId(iWgIds[index].iId);
       
   179         
       
   180         uidBuffer.AppendFormat(KUidFormat, uid.iUid);
       
   181         
       
   182         index++;
       
   183         }
       
   184     
       
   185     Write(uidBuffer);
       
   186     }
       
   187 
       
   188 void COomLogger::LogFreeMemory()
       
   189     {
       
   190     TMemoryInfoV1Buf meminfo;
       
   191     UserHal::MemoryInfo(meminfo);
       
   192     TInt freeMem = meminfo().iFreeRamInBytes;
       
   193 
       
   194     // Save the free memory to a descriptor which will be written later
       
   195     iWriteBuffer.AppendFormat(KMemorySampleLoggingString(), freeMem);
       
   196     }
       
   197 
       
   198 COomLogger::COomLogger(RWsSession& aWs, RFs& aFs) : CTimer(EPriorityStandard), iWs(aWs), iFs(aFs)
       
   199     {
       
   200     }
       
   201 
       
   202 void COomLogger::ConstructL()
       
   203     {
       
   204     CActiveScheduler::Add(this);
       
   205     
       
   206     CTimer::ConstructL();
       
   207     
       
   208     TFileName oldLogFileName;
       
   209     TFileName newLogFileName;
       
   210     TChar driveChar = iFs.GetSystemDriveChar();
       
   211     oldLogFileName.Append(driveChar);
       
   212     oldLogFileName.Append(KOomOldLogFile);
       
   213     newLogFileName.Append(driveChar);
       
   214     newLogFileName.Append(KOomLogFile);
       
   215     // If there is an existing log then copy it, this will be the log that can be sent to the PC
       
   216     // Without this feature then you can't get the logs off of the device because the "live" log will always be is use.
       
   217     CFileMan* fileMan = CFileMan::NewL(iFs);
       
   218     CleanupStack::PushL(fileMan);
       
   219     fileMan->Copy(newLogFileName, oldLogFileName);
       
   220     CleanupStack::PopAndDestroy(fileMan);
       
   221     
       
   222     // Create the log file, or open it if is already exists (note that the directory must already be present
       
   223     TInt err = iFile.Create(iFs, KOomLogFile, EFileShareAny | EFileWrite);
       
   224     if (KErrNone != err)
       
   225         {
       
   226         err = iFile.Open(iFs, KOomLogFile, EFileShareAny | EFileWrite);
       
   227         }
       
   228     
       
   229     if (KErrNone == err)
       
   230         {
       
   231         iIsOpen = ETrue;
       
   232         
       
   233         // Append all new data to the end of the file
       
   234         TInt offset = 0;
       
   235         iFile.Seek(ESeekEnd, offset);
       
   236         }
       
   237     
       
   238     // Reserve enough space to build an app list later.
       
   239     iWgIds.ReserveL(KPreallocatedSpaceForAppList);
       
   240     // Reserve enough space for CApaWindowGroupName.
       
   241     iWgName = CApaWindowGroupName::NewL(iWs);
       
   242     iWgNameBuf = HBufC::NewL(CApaWindowGroupName::EMaxLength);
       
   243     (*iWgNameBuf) = KDummyWgName;
       
   244     iWgName->SetWindowGroupName(iWgNameBuf);    // iWgName takes ownership of iWgNameBuf*/
       
   245 
       
   246     }
       
   247 
       
   248 void COomLogger::ColapseWindowGroupTree()
       
   249     {
       
   250     // start from the front, wg count can reduce as loop runs
       
   251     for (TInt ii=0; ii<iWgIds.Count();)
       
   252         {
       
   253         RWsSession::TWindowGroupChainInfo& info = iWgIds[ii];
       
   254         if (info.iParentId > 0)        // wg has a parent
       
   255             {
       
   256             // Look for the parent position
       
   257             TInt parentPos = ii;        // use child pos as not-found signal
       
   258             TInt count = iWgIds.Count();
       
   259             for (TInt jj=0; jj<count; jj++)
       
   260                 {
       
   261                 if (iWgIds[jj].iId == info.iParentId)
       
   262                     {
       
   263                     parentPos = jj;
       
   264                     break;
       
   265                     }
       
   266                 }
       
   267 
       
   268             if (parentPos > ii)  // parent should be moved forward
       
   269                 {
       
   270                 iWgIds[ii] = iWgIds[parentPos];
       
   271                 iWgIds.Remove(parentPos);
       
   272                 }
       
   273             else if (parentPos < ii)  // parent is already ahead of child, remove child
       
   274                 iWgIds.Remove(ii);
       
   275             else                    // parent not found, skip
       
   276                 ii++;
       
   277             }
       
   278         else    // wg does not have a parent, skip
       
   279             ii++;
       
   280         }
       
   281     }
       
   282 
       
   283 TUid COomLogger::GetUidFromWindowGroupId(TInt aWgId)
       
   284     {
       
   285     // get the app's details
       
   286     TPtr wgPtr(iWgNameBuf->Des());
       
   287     
       
   288     TUid uid;
       
   289     
       
   290     TInt err = iWs.GetWindowGroupNameFromIdentifier(aWgId, wgPtr);
       
   291     
       
   292     if (KErrNone != err)
       
   293         // If there is an error then set the UID to 0;
       
   294         {
       
   295         uid.iUid = 0;
       
   296         }
       
   297     else
       
   298         {
       
   299         iWgName->SetWindowGroupName(iWgNameBuf);
       
   300         uid = iWgName->AppUid(); // This UID comes from the app, not the mmp!
       
   301         }
       
   302     
       
   303     return uid;
       
   304     }
       
   305 
       
   306 #endif //_DEBUG