如何使用C ++测量Linux中切换进程上下文的时间?

时间:2014-01-15 18:53:26

标签: c++ linux process

我需要使用C ++来测量上下文切换的时间。我知道我可以简单地从C ++代码访问C函数,但任务是尽可能避免使用C语言。我在互联网上搜索了这个,但发现只有这样做的方法使用C.有没有办法在C ++中使用OS?来自pipe(...)的{​​{1}},来自unistd.h的{​​{1}}和其他人的sched_setaffinity(...)类似物?

2 个答案:

答案 0 :(得分:1)

更新2017-06-30:添加了示例代码

Are there any ways to work with OS in C++?

您引用的所有C函数都可以通过直接包含访问。 例如:

#include "pthread.h"

在C ++编译中,自动神奇地获得extern“C”d。

您的链接在Linux上需要-lrt和-pthread

Any analogs of pipe(...) from unistd.h, sched_setaffinity(...) 

不是类比,构建链接到真正的“C”Linux函数。


I need to measure the time of context switching using C++ means.

我通过重复一些动作1到10秒来计算持续时间,并计算循环完成的次数。

在我最新的次要基准测试中,完全用C ++编写(但不使用C ++ 11功能),我

  • 构建节点的链接列表
  • 每个节点都有自己的线程
  • 每个线程拥有2个指向pthread_mutex信号量的指针(输入和输出)
  • 每个线程主体等待其输入信号量发出信号(semTake())
  • 在唤醒时,线程主体将(semGive())发送到其输出信号量并且确实如此 几乎没有更多
  • 将N个线程的信号量分发给节点线程并关闭循环 在列表的末尾(即end-list-node输出信号量句柄指向 begin-list-node输入信号量句柄)

  • 主要任务,用semGive()开始连锁反应,等待10秒钟(使用 usleep),然后设置每个线程都可以看到的标志。


示例在6岁的戴尔上运行。


Compilation started at Wed Jan 15 22:31:33

./lmbm101
lmbm101: context-switch duration .. wait up to 10 seconds while measuring.
  switch enforced using pthread_mutex semaphores

C5   bogomips:  5210.77   5210.77  
  686.56  kilo  m_thread_switch invocations in 10.88 sec   (10000088 us)
  68.6554  kilo  m_thread_switch events per second
  14.5655  u seconds per m_thread_switch event
pid = 12188

now (52d760af): 22:31:43
bdtod 2014/01/15 22:31:43  minod=1351  iod=91  secod=81103  soi=104

我在C ++ 11发布之前做了这个小基准测试。这段代码是用C ++ 11编译的,但不使用C ++ 11任务......对我来说是未来的努力。


更新2017-06-30 - 逾期更新...

我写了这个示例代码2017-04。我现在倾向于使用std :: vector来处理各种事情。以前的测量没有。类似的技术,但简化的结果报告。

#include <chrono>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <thread>
#include <vector>

// see EngFormat-Cpp-master.zip
#ifndef                 ENG_FORMAT_H_INCLUDED
#include "../../bag/src/eng_format.hpp"        // to_engineering_string(), from_engineering_string()
#endif

#include <cassert>


#include <semaphore.h>  // Note 1 - Ubuntu / Posix feature access, see PPLSEM_t


namespace DTB // doug's test box
{
   // Note 2 - typedefs to simplify chrono access
   // 'compressed' chrono access --------------vvvvvvv
   typedef std::chrono::high_resolution_clock  HRClk_t; // std-chrono-hi-res-clk
   typedef HRClk_t::time_point                 Time_t;  // std-chrono-hi-res-clk-time-point
   typedef std::chrono::microseconds           NS_t;    // std-chrono-nanoseconds
   typedef std::chrono::microseconds           US_t;    // std-chrono-microseconds
   typedef std::chrono::microseconds           MS_t;    // std-chrono-milliseconds
   using   namespace std::chrono_literals;          // support suffixes like 100ms, 2s, 30us
   // examples:
   //   Time_t testStart_us = HRClk_t::now();
   //   auto  testDuration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - testStart_us);
   //   auto         count_us =       testDuration_us.count();
   //   or
   //   std::cout << "  complete " << testDuration_us.count() << " us" << std::endl;



   // C++ access to Linux semaphore via Posix
   // Posix Process Semaphore, set to Local mode (unnamed, unshared)
   class PPLSem_t
   {
   public:               // shared-between-threads--v  v--initial-value is unlocked
      PPLSem_t()   { assert(0 == ::sem_init(&m_sem, 0, 1)); } // ctor
      ~PPLSem_t()  { assert(0 == ::sem_destroy(&m_sem));    } // dtor

      int lock()   { return (::sem_wait(&m_sem)); }   // returns 0 when success, else -1
      int unlock() { return (::sem_post(&m_sem)); }   // returns 0 when success, else -1

      void wait()  { assert(0 == lock());   }
      void post()  { assert(0 == unlock()); }

   private:
      ::sem_t m_sem;
   };
   // POSIX is an api, this C++ class simplifies use
   //    sem_wait and sem_post are possibly assembly for best performance



   // Note 3 - locale what now?
   // insert commas from right to left -- change 1234567890 to 1,234,567,890
   // input 's' is the digits-to-the-left-of-the-decimal-point
   // returns s contents with inserted comma's
   std::string digiComma(std::string s)
   {  //vvvvv--sSize must be signed int of sufficient size
      int32_t sSize = static_cast<int32_t>(s.size());
      if (sSize > 3)
         for (int32_t indx = (sSize - 3); indx > 0; indx -= 3)
            s.insert(static_cast<size_t>(indx), 1, ',');
      return(s);
   }


   const std::string dashLine("  --------------------------------------------------------------\n");


   // Note 5 - thread sync to wall clock
   // action: pauses a thread, resume thread action at next wall-clock-start-of-second
   void sleepToWallClockStartOfSec(std::time_t t0 = 0)
   {
      if (0 == t0) { t0 = std::time(nullptr); }
      while(t0 == std::time(nullptr))         {
         std::this_thread::sleep_for(100ms);  } // good-neighbor-thread
   }
   // a good-neighbor-thread delay does not 'hog' a processor


   // Note 4 - typedef examples to simplify
   // create new types based on vector ... suffix '_t' reminds that this is a type
   typedef std::vector<uint>           UintVec_t;
   typedef std::vector<uint>           TIDSeqVec_t;
   typedef std::vector<std::thread*>   Thread_pVec_t;


   // measure -std=C++14 std::thread average context switch duration
   //                                enforced with one PPLSem_t
   class Q6_t
   {
      // private data
      const uint        MaxThreads;        // thread count
      const uint        MaxSecs;           // seconds of test
      const std::string m_TIDSeqPFN;     // capture tid seq to ram (write to file later)
      //
      uint           m_thrdSwtchCount;   // count incremented by all threads
      //
      bool           m_done;             // main to threads: cease and desist
      uint           m_rdy;              // threads to main: thread is ready! (running)
      PPLSem_t       m_sem;              // one semaphore shared by all threads
      //
      UintVec_t      m_thrdRunCountVec;  // counts incremented per thread
      TIDSeqVec_t    m_TIDSeq_Vec;       // sequence (order) of thread execution
      Thread_pVec_t  m_thread_pVec;      // vector of thread pointers

   public:

      Q6_t()  // default ctor
         : MaxThreads(10)           // total threads
         , MaxSecs(10)              // controlled seconds of test
         , m_TIDSeqPFN("./Q6.txt")  // where put data file
           //
         , m_thrdSwtchCount(0)
           //
         , m_done(false)            // main() to threads: cease and desist
         , m_rdy(0)                 // threads to main(): thread is ready!
           // m_sem                 // default ctor ok
           //
           // m_thrdRunCountVec     // default ctor ok
           // m_TIDSeq_Vec          // default ctor ok
           // m_thread_pVec         // default ctor ok
         {
            for (size_t i = 0; i < MaxThreads; ++i) {
               m_thrdRunCountVec.push_back(0);   // 0 each per-thread counter
            }
            // your results -----vvvvvvvv----will vary
            m_TIDSeq_Vec.reserve(45000000);  // observed as many as 42,000,000 on my old Dell
            m_thread_pVec.reserve(MaxThreads);
            // DO NOT start threads (m_thread_pVec) yet
         } // AciveObj_t()



      ~Q6_t()
         {
            // m_TIDSeq_Vec,
            while(m_thread_pVec.size()) {              // more to pop and delete
               std::thread* t = m_thread_pVec.back();  // return last element
               m_thread_pVec.pop_back();               // remove last element
               delete t;                               // delete thread
            }
            // m_thrdRunCountVec;
            // m_TIDSeqPFN, m_sem, m_rdy; m_done;
            // m_thrdSwtchCount; MaxSecs; MaxThreads;
         } // ~Q6_t()



      // Q6_t::main(..)  runs in context thread 'main()', invoked in function main()
      int main(std::string label)
         {
            std::cout << dashLine << "  " << MaxSecs << " second measure of "
                      << MaxThreads << " threads, 1 PPLSem_t " << label << "\n"
                      << "  output: " << m_TIDSeqPFN << '\n'<< std::endl;

            assert(0 == m_sem.lock());    // take posession of m_sem
            // now all thread will block at critical section entry (in onceThruCritSect())
            std::cout << "\n  block threads at crit sect   " << std::endl;

            createAndActivateThreads();

            long int durationUS = 0;

            releaseThreadsAndWait(durationUS); // run threads run

            std::cout << "\n" << std::endl
                      << report(" 'thread context switch' ",
                                m_thrdSwtchCount, durationUS);

            reportThreadActionCounts();

            writeTIDSeqToQ6_txt();

            reportMainStackSize();

            measure_LockUnlock();        // with no context switch, no collision

            return(0);
         } // int main() // in 'main' context


   private:


      void onceThru(uint id)  // a crit section
         {
            assert(0 == m_sem.lock());      // critical section entry
            {
               m_thrdSwtchCount      += 1;     // 'work'
               m_thrdRunCountVec[id] += 1;     // diagnostic - thread work-balance
               m_TIDSeq_Vec.push_back(id);     // thread sequence capture
            }
            assert(0 == m_sem.unlock());    // critical section exit
         }



      // thread entry point
      void threadRun(uint id)
         {
            std::cout << '.' << id << std::flush;  //  ".0.1.2.3.4.5.6.7.8.9"
            m_rdy |= (1 << id);     // thread to main: i am ready
            do {

               onceThru(id);

               if (m_done) break; // exit when done   tbr - FIXME -- rare hang

            }while(true);
         }



      // main() context: create and activate std::thread's with new
      void createAndActivateThreads() // main() context
         {
            std::cout << "  createAndActivateThreads()  ";
            Time_t start_us = HRClk_t::now();
            for (uint id = 0; id < MaxThreads; ++id)
            {
               // std::thread activates when instance created
               std::thread*  thrd = new
                  std::thread(&Q6_t::threadRun, this, id);
               // method-------^^^^^^^^^^^^^^^        ^^--single param for method
               // instance*---------------------^^^^
               assert(nullptr != thrd);

               // create handshake mask for unique 'id' bit of m_rdy
               uint mask = (1 << id);

               // wait for bit set in m_rdy by thread
               while ( ! (mask & m_rdy) ) {
                  std::this_thread::sleep_for(100ms); // not a poll
               }
               // thread has confirmed to main() that it is running

               // capture pointer to invoke join's
               m_thread_pVec.push_back(thrd);
            }
            auto  duration_us =
               std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
            std::cout << "   (" << digiComma(std::to_string(duration_us.count()))
                      << " us)" << std::endl;

            sleepToWallClockStartOfSec(); // start-of-second

         } // void createAndActivateThreads()



      // main() context: measure average context switch duration
      //    by releasing threads to run
      void releaseThreadsAndWait(long int& count_us)
         {
            Time_t testStart_us = HRClk_t::now();

            // thread 'main()' is current owner of this semaphore - see "Q6_t::main()"
            assert(0 == m_sem.unlock()); // release the hounds

            std::cout << "  releaseThreadsAndWait        " << std::flush;

            // progress indicator to user
            for (size_t i = 0; i < MaxSecs; ++i) // let threads switch for 10 seconds
            {
               sleepToWallClockStartOfSec();    // 'main()' sync's to wall clock
               std::cout << (MaxSecs-i-1) << ' ' << std::flush; // "9 8 7 6 5 4 3 2 1 0"
            }

            // tbr - dedicated mutex for this single-write / multiple read ?  or std::atomic ?
            m_done = true;      // command threads to exit - all threads can see m_done

            auto  testDuration_us =
               std::chrono::duration_cast<US_t>(HRClk_t::now() - testStart_us);
            count_us = testDuration_us.count();

            // tbr - main() shall confirm all threads complete
            // tbr - measure how long to detect m_done


            Time_t joinStart_us = HRClk_t::now();
            std::cout << "\n  join threads                 ";
            for (size_t i = 0; i < MaxThreads; ++i)
            {
               m_thread_pVec[i]->join();           // main() waits here for thread[i] completion
               std::cout << ". " << std::flush;
            }
            auto  joinDuration_us =
               std::chrono::duration_cast<US_t>(HRClk_t::now() - joinStart_us);
            std::cout << "   (" << digiComma(std::to_string(joinDuration_us.count()))
                      << " us)" << std::endl;

         } // void releaseThreadsAndWait(long int& count_us)



      void reportThreadActionCounts()
         {
            std::cout << "\n  each thread run count: \n ";
            uint      sum = 0;
            for (auto it : m_thrdRunCountVec)
            {
               std::cout << std::setw(11) << digiComma(std::to_string(it));
               sum += it;
            }
            std::cout << std::endl;
            uint diff = (sum - m_thrdSwtchCount);


            std::cout << ' ';
            double maxPC = 0.0;
            double minPC = 100.0;
            for (auto it : m_thrdRunCountVec)
            {
               double percent = static_cast<double>(it) / static_cast<double>(sum);
               if(percent > maxPC) maxPC = percent;
               if(percent < minPC) minPC = percent;
               std::cout << std::setw(11) << (percent * 100);
            }
            std::cout << "  (% of total)\n\n  total : " << digiComma(std::to_string(sum));

            if (diff) std::cout << "  (diff: " << diff << ")";

            std::cout << "   note variability --   min : " << (minPC*100)
                      << "%    max : " << (maxPC*100) << "%" << std::endl;
         } // void reportThreadActionCounts()



      void writeTIDSeqToQ6_txt() //  m_TIDSeq_Vec - record sequence of thread access to critsect
         {
            size_t sz = m_TIDSeq_Vec.size();
            std::cout << '\n' << dashLine << "  writing Thread ID sequence of "
                      << digiComma(std::to_string(sz)) << " values to "
                      << m_TIDSeqPFN << std::endl;

            Time_t writeStart_us = HRClk_t::now();

            do {
               std::ofstream Q6cout(m_TIDSeqPFN);

               if ( ! Q6cout.good() )
               {
                  std::cerr << "not able to open for write: " << m_TIDSeqPFN << std::endl;
                  break;
               }

               size_t lnSz = 0;
               for (auto it : m_TIDSeq_Vec)
               {
                  // encode Thread ID  uints:           0   1   2   3   4   5   6   7   8   9
                  // to letters 'A' thru 'J': vvvvvv   'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J'
                  Q6cout << static_cast<char>(it+'A');
                  // whitespace not needed

                  if (++lnSz > 100) { Q6cout << std::endl; lnSz = 0; } // 100 chars per line
               }
               Q6cout << '\n' << std::endl;

               Q6cout.close();

            } while(0);

            auto wDuration_us = std::chrono::duration_cast<US_t>
               ( HRClk_t::now() - writeStart_us );

            std::cout << "  complete: "
                      << digiComma(std::to_string(wDuration_us.count()))
                      << " us" << std::endl;
         } // writeTIDSeqToQ6_txt



      std::string report(std::string lbl, uint64_t eventCount, uint64_t duration_us)
         {
            std::stringstream ss;
            ss << "  " << to_engineering_string(static_cast<double>(eventCount),9,eng_prefixed)
               << lbl << " events in " << digiComma(std::to_string(duration_us)) << " us" << std::endl;

            double eventsPerSec = (1000000.0*(static_cast<double>(eventCount))/
                                   static_cast<double>(duration_us));

            ss << "  " << to_engineering_string(eventsPerSec,9,eng_prefixed)
               << lbl << " events per second\n  "
               << to_engineering_string((1.0/eventsPerSec), 9, eng_prefixed)
               << " sec per " << lbl << " event " << std::endl;
            return(ss.str());
         } // std::string report(std::string lbl, uint64_t eventCount, uint64_t duration_us)


      // Note 6 - stack size -> use POSIX 'pthread_attr_...' API
      void reportMainStackSize()
         {
            pthread_attr_t tattr;
            int stat = pthread_attr_init (&tattr);
            assert(0 == stat);

            size_t size;
            stat = pthread_attr_getstacksize(&tattr, &size);
            assert(0 == stat);

            std::cout << '\n' << dashLine << "  Stack Size: "
                      << digiComma(std::to_string(size))
                      << "    [of 'main()' by pthread_attr_getstacksize]\n"
                      << std::endl;
            stat = pthread_attr_destroy(&tattr);
            assert(0 == stat);
         } // void reportMainStackSize()


      // Note 7 - semaphore API performance
      // measure duration when no context switch (i.e. no thread 'collision')
      void measure_LockUnlock()
         {
            //PPLSem_t*  sem1 = new PPLSem_t;
            //assert(nullptr != sem1);
            PPLSem_t sem1;
            size_t   count1 = 0;
            size_t   count2 = 0;
            std::cout << dashLine << "  3 second measure of lock()/unlock()"
                      << " (no collision) " << std::endl;
            time_t t0 = time(0) + 3;

            Time_t start_us = HRClk_t::now();
            do {
               assert(0 == sem1.lock());   count1 += 1;
               assert(0 == sem1.unlock()); count2 += 1;
               if(time(0) > t0)  break;
            }while(1);
            auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

            assert(count1 == count2);
            std::cout << report (" 'sem lock()+unlock()' ", count1, duration_us.count());

            std::cout << "\n";
         } // void mainMeasures_LockUnlock()

   };  // class Q6_t

} // namespace DTB


int main(int argc, char* argv[] )
{
   std::cout << "\nargc: " << argc << '\n' << std::endl;
   for (int i=0; i<argc; i+=1) std::cout  << argv[i] << "    ";
   std::cout << "\n" << std::endl;

   setlocale(LC_ALL, "");
   std::ios::sync_with_stdio(false);
   {
      std::time_t t0 = std::time(nullptr);
      std::cout << "  " << std::asctime(std::localtime(&t0)) << std::endl;;
      DTB::sleepToWallClockStartOfSec(t0);
   }

   DTB::Time_t main_start_us = DTB::HRClk_t::now();
   int retVal = 0;
   {
      DTB::Q6_t  q6;
      retVal  =  q6.main(" Q6::main() ");
   }
   auto duration_us = std::chrono::duration_cast<DTB::US_t>
      (DTB::HRClk_t::now() - main_start_us);

   std::cout << "  FINI  "
             << DTB::digiComma(std::to_string(duration_us.count()))
             << " us" << std::endl;
   return(retVal);
}

旧戴尔的典型输出。

  Fri Jun 30 15:30:13 2017

  --------------------------------------------------------------
  10 second measure of 10 threads, 1 PPLSem_t  Q6::main() 
  output: ./Q6.txt


  block threads at crit sect   
  createAndActivateThreads()  .0.1.2.3.4.5.6.7.8.9   (1,002,120 us)
  releaseThreadsAndWait        9 8 7 6 5 4 3 2 1 0 
  join threads                 . . . . . . . . . .    (2,971 us)


  31.07730700 M 'thread context switch'  events in 10,021,447 us
  3.101079814 M 'thread context switch'  events per second
  322.4683207 n sec per  'thread context switch'  event 

  each thread run count: 
   3,182,496  3,252,929  3,245,473  3,150,344  3,411,918  2,936,982  2,978,690  3,029,319  3,004,926  2,884,230
     10.2406    10.4672    10.4432    10.1371    10.9788    9.45057    9.58478    9.74769     9.6692    9.28082  (% of total)

  total : 31,077,307   note variability --   min : 9.28082%    max : 10.9788%

  --------------------------------------------------------------
  writing Thread ID sequence of 31,077,307 values to ./Q6.txt
  complete: 3,025,289 us

  --------------------------------------------------------------
  Stack Size: 8,720,384    [of 'main()' by pthread_attr_getstacksize]

  --------------------------------------------------------------
  3 second measure of lock()/unlock() (no collision) 
  173.2359360 M 'sem lock()+unlock()'  events in 3,902,491 us
  44.39111737 M 'sem lock()+unlock()'  events per second
  22.52702926 n sec per  'sem lock()+unlock()'  event 

  FINI  18,957,304 us

Q6.txt行的样本长度为100个字符。

AABABABABAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

最后几行

BJBJBJBJBJBJBJBJBBHHHHHHHHHHHHHHHHHBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAA
AAAAAAAAAAAAAAAAAAAAAABABABABAABABBAAAAAAAAAAAAAAAAAAAAAAAAAAAAABABABBGGGGGGGGGGGGGGGBGBGBGBGBGBGBGBG
BGBGBGBGBGBGBGBGBGBBGBGBGBGBGBGBGBBHHHHHHHHHHHHHHHHBHBHBHBHBHBHBHBHBHBHBHBHBHBHBHBBHBHBHBHBBJJJJJJJJJ
JJJJJJJJJBBJBBBJBJBJBJBJBJBBJBJBJBJBJBJBJBJBJBBEEEEEEEEEEEEEEEEEBEBEBEBEBEBEBEBEBEBEBEBEBEBEBBEBEBEBE
BEBEBEBEBEBEBEBEBEBEBEBEBEBEBBEBEBEBBBBEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEBEBBEBEBEBEEEEEEEEEEEEEEEEEEEEEE
EEEEEEEEBEBEBEBEEBEBEBEBEBBIIIIIIIIIIIIIIIBBIIIBIBBFFFFFFFFFFFFFFFBBFFBBFBFBFBFBFFBBGGGGGGGGGGGGGGGGG
BBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGBGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
GGBCIHFJDAE

答案 1 :(得分:1)

  
    

您引用的所有C函数都可以通过以下方式访问     直接包括。

  
     

谢谢,我知道这个事实,但任务是避免C和使用   C ++尽可能。

我的C ++代码中没有C代码,只是调用extern“C” Linux提供的功能。没有单独的C ++ Linux集 函数调用。 Linux API(到os服务)由 C库和头文件。我知道无法避免或解决 Linux API,所以也许我不知道你在暗示/问什么。

  
    

我通过重复一些动作1至10秒来测量持续时间,     并计算循环完成的次数。

  
     你可以解释一下吗?

考虑代码段

{
  uint64_t microsecStart = getSystemMicroSecond();

    //convert linear time to broken-down/calendar time
    local_tm = *localtime_r (&linear_time, &local_tm); 

    uint64_t microsecDuration = getSystemMicroSecond() - microsecStart;
}

此操作通常太快,无法以这种简单的方式进行测量, 基本上是一个delta-microsecond,转换将在a之前结束 微秒可能会改变。

为了快速测量某些东西,我们围绕着它的动作 兴趣,并计算循环,并在3秒后开出。

uint64_t microsecStart = getSystemMicroSecond();
uint32_t loopCount = 0;
time_t t0 = time(0) + 3; // loop for < 3 seconds
do
{   
   //convert linear time to broken-down/calendar time
   local_tm = *localtime_r (&linear_time, &local_tm); 

   time_t t1 = time(0);
   if(t1 != t0) break;
   loopCount += 1;

} while(1);
uint64_t microsecDuration = getSystemMicroSecond() - microsecStart;

在这个循环中,时间(0)功能非常快。

  • 时间(0)需要约75纳秒(在我的戴尔桌面上)

所以时间(0)不会显着延长测量值。

但足够快,可以准确测量当地持续时间

  • localtime_r需要~353纳秒

当这些旋转完成时,测试创建了一个loopCount,并且a 循环外的持续时间测量提供更一致的测量 持续时间...,然后我们可以计算'平均' 每个事件的持续时间。

  

您是否忽略了进程运行的时间?

是。因为我知道上下文切换是2阶   比函数调用慢,这并不困难   最小化线程活动没有/最小影响   关于测量。

  

与切换时间相比,它是否很小?

在此测试中,线程递增一个数字,测试一个标志,然后动作   作为一个好邻居(即这些线程将处理器交给了   尽快)。这些小动作对于这些微不足道的行为微不足道   上下文切换的成本。

我6岁的戴尔的数字是3个数量级的差异。

简单函数调用:即时间(0)&lt; 75 e-9秒

线程上下文切换&lt; 15 e-6秒   用信号量强制执行

其他活动可以影响结果,但我认为 微不足道的。我的每个“螺纹开关和我的14 us的结果 信号量发送“比最好的结果更长,但不是 足够长的时间来影响我的设计决策。有可能 改善这种测量,但我买不起硬件。

Linux提供了一些线程或任务优先级的想法,但我没有 探索了他们。当我认真寻找“更好”的测量时, 我想我会断开以太网,关闭任何繁忙的工作......但是 我没有运行编译,也没有复制文件,也没有运行备份 当我测量时,任何明显的cpu周期消费者。机器是 基本上空闲。只是时钟滴答,定时器到期,内存 刷新,以及其他一些必须继续的事情。

为了好玩或兴趣,您可以启动系统监视器实用程序, 单击%CPU标签1或2次,并将最繁忙的任务带到 顶部......你应该发现最繁忙的任务是ta-da:系统 监控可能是2个cpu之一的3%。所有其他任务都是 基本上等待某事,并触发0%的负载。

最后你可能会这样想......

你正在编写一个在非典型机器上运行的程序吗?   或者你的目标是否与你的开发机器相似?

你打算关闭中断吗? i / o频道?以太网?控制   优先?或者你的目标是否有用。

恕我直言,系统运行时我的有用(linux)系统中的运行任务 一般来说,除了等待我的下一次击键之外什么都不做 在大多数10秒的测试中什么都不做。

我认为这些努力中最重要的一点是:

 function calls are more than 100x faster than context switches.