Home | History | Annotate | Download | only in common
      1 /****************************************************************************
      2 * Copyright (C) 2014-2015 Intel Corporation.   All Rights Reserved.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice (including the next
     12 * paragraph) shall be included in all copies or substantial portions of the
     13 * Software.
     14 *
     15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21 * IN THE SOFTWARE.
     22 *
     23 * @file rdtsc_buckets.h
     24 *
     25 * @brief declaration for rdtsc buckets.
     26 *
     27 * Notes:
     28 *
     29 ******************************************************************************/
     30 #pragma once
     31 
     32 #include "os.h"
     33 #include <vector>
     34 #include <mutex>
     35 #include <sstream>
     36 
     37 #include "rdtsc_buckets_shared.h"
     38 
     39 
     40 // unique thread id stored in thread local storage
     41 extern THREAD UINT tlsThreadId;
     42 
     43 //////////////////////////////////////////////////////////////////////////
     44 /// @brief BucketManager encapsulates a single instance of the buckets
     45 ///        functionality. There can be one or many bucket managers active
     46 ///        at any time.  The manager owns all the threads and
     47 ///        bucket information that have been registered to it.
     48 class BucketManager
     49 {
     50 public:
     51     BucketManager() { }
     52     ~BucketManager();
     53 
     54     // removes all registered thread data
     55     void ClearThreads()
     56     {
     57         mThreadMutex.lock();
     58         mThreads.clear();
     59         mThreadMutex.unlock();
     60     }
     61 
     62     // removes all registered buckets
     63     void ClearBuckets()
     64     {
     65         mThreadMutex.lock();
     66         mBuckets.clear();
     67         mThreadMutex.unlock();
     68     }
     69 
     70     /// Registers a new thread with the manager.
     71     /// @param name - name of thread, used for labels in reports and threadviz
     72     void RegisterThread(const std::string& name);
     73 
     74     /// Registers a new bucket type with the manager.  Returns a unique
     75     /// id which should be used in subsequent calls to start/stop the bucket
     76     /// @param desc - description of the bucket
     77     /// @return unique id
     78     UINT RegisterBucket(const BUCKET_DESC& desc);
     79 
     80     // print report
     81     void PrintReport(const std::string& filename);
     82 
     83 
     84     // start capturing
     85     void StartCapture();
     86 
     87     // stop capturing
     88     INLINE void StopCapture()
     89     {
     90         mCapturing = false;
     91 
     92         // wait for all threads to pop back to root bucket
     93         bool stillCapturing = true;
     94         while (stillCapturing)
     95         {
     96             stillCapturing = false;
     97             for (const BUCKET_THREAD& t : mThreads)
     98             {
     99                 if (t.level > 0)
    100                 {
    101                     stillCapturing = true;
    102                     continue;
    103                 }
    104             }
    105         }
    106 
    107         mDoneCapturing = true;
    108         printf("Capture Stopped\n");
    109     }
    110 
    111     // start a bucket
    112     // @param id generated by RegisterBucket
    113     INLINE void StartBucket(UINT id)
    114     {
    115         if (!mCapturing) return;
    116 
    117         SWR_ASSERT(tlsThreadId < mThreads.size());
    118 
    119         BUCKET_THREAD& bt = mThreads[tlsThreadId];
    120 
    121         uint64_t tsc = __rdtsc();
    122 
    123         {
    124             if (bt.pCurrent->children.size() < mBuckets.size())
    125             {
    126                 bt.pCurrent->children.resize(mBuckets.size());
    127             }
    128             BUCKET &child = bt.pCurrent->children[id];
    129             child.pParent = bt.pCurrent;
    130             child.id = id;
    131             child.start = tsc;
    132 
    133             // update thread's currently executing bucket
    134             bt.pCurrent = &child;
    135         }
    136 
    137 
    138         bt.level++;
    139     }
    140 
    141     // stop the currently executing bucket
    142     INLINE void StopBucket(UINT id)
    143     {
    144         SWR_ASSERT(tlsThreadId < mThreads.size());
    145         BUCKET_THREAD &bt = mThreads[tlsThreadId];
    146 
    147         if (bt.level == 0)
    148         {
    149             return;
    150         }
    151 
    152         uint64_t tsc = __rdtsc();
    153 
    154         {
    155             if (bt.pCurrent->start == 0) return;
    156             SWR_ASSERT(bt.pCurrent->id == id, "Mismatched buckets detected");
    157 
    158             bt.pCurrent->elapsed += (tsc - bt.pCurrent->start);
    159             bt.pCurrent->count++;
    160 
    161             // pop to parent
    162             bt.pCurrent = bt.pCurrent->pParent;
    163         }
    164 
    165         bt.level--;
    166     }
    167 
    168     INLINE void AddEvent(uint32_t id, uint32_t count)
    169     {
    170         if (!mCapturing) return;
    171 
    172         SWR_ASSERT(tlsThreadId < mThreads.size());
    173 
    174         BUCKET_THREAD& bt = mThreads[tlsThreadId];
    175 
    176         // don't record events for threadviz
    177         {
    178             if (bt.pCurrent->children.size() < mBuckets.size())
    179             {
    180                 bt.pCurrent->children.resize(mBuckets.size());
    181             }
    182             BUCKET &child = bt.pCurrent->children[id];
    183             child.pParent = bt.pCurrent;
    184             child.id = id;
    185             child.count += count;
    186         }
    187     }
    188 
    189 private:
    190     void PrintBucket(FILE* f, UINT level, uint64_t threadCycles, uint64_t parentCycles, const BUCKET& bucket);
    191     void PrintThread(FILE* f, const BUCKET_THREAD& thread);
    192 
    193     // list of active threads that have registered with this manager
    194     std::vector<BUCKET_THREAD> mThreads;
    195 
    196     // list of buckets registered with this manager
    197     std::vector<BUCKET_DESC> mBuckets;
    198 
    199     // is capturing currently enabled
    200     volatile bool mCapturing{ false };
    201 
    202     // has capturing completed
    203     volatile bool mDoneCapturing{ false };
    204 
    205     std::mutex mThreadMutex;
    206 
    207     std::string mThreadVizDir;
    208 
    209 };
    210 
    211 
    212 // C helpers for jitter
    213 void BucketManager_StartBucket(BucketManager* pBucketMgr, uint32_t id);
    214 void BucketManager_StopBucket(BucketManager* pBucketMgr, uint32_t id);
    215