সি ++ ব্যবহার করে ন্যানো সেকেন্ডে সময় সরবরাহ করতে টাইমার ফাংশন


101

আমি কোনও এপিআইতে একটি মান ফেরত দিতে যে সময়টি নিয়েছিল তা গণনা করতে চাই। এই জাতীয় পদক্ষেপের জন্য নেওয়া সময়টি ন্যানো সেকেন্ডের ব্যবধানে। যেহেতু API হ'ল সি ++ শ্রেণি / ফাংশন, তাই টাইমরএইচটি একইভাবে সঞ্চারিত করতে আমি ব্যবহার করছি:

  #include <ctime>
  #include <cstdio>

  using namespace std;

  int main(int argc, char** argv) {

      clock_t start;
      double diff;
      start = clock();
      diff = ( std::clock() - start ) / (double)CLOCKS_PER_SEC;
      cout<<"printf: "<< diff <<'\n';

      return 0;
  }

উপরের কোডটি সেকেন্ডে সময় দেয়। ন্যানো সেকেন্ডে এবং আরও নির্ভুলতার সাথে আমি কীভাবে তা পেতে পারি?


উপরের কোডটি সেকেন্ডে গণনা করে, আমি উত্তরটি ন্যানো সেকেন্ডে পেতে চাই ...
gagneet

একটি ভাল উত্তর পেতে প্রশ্নে প্ল্যাটফর্ম যুক্ত করতে হবে (এবং পাশাপাশি শিরোনামেও)।
প্যাট্রিক জনমেয়ার

সময় পাওয়ার পাশাপাশি, একজনকে মাইক্রোব্যাঙ্কমার্কিংয়ের ক্ষেত্রে সমস্যাগুলি সন্ধান করা উচিত (যা অত্যন্ত জটিল) - কেবলমাত্র একটি সম্পাদন করা, এবং শুরু এবং শেষ সময় পাওয়া, যথেষ্ট যথাযথতা দেওয়ার সম্ভাবনা কম।
ব্লেজারব্ল্যাড

@ ব্লাইজারব্ল্যাড: বিশেষত যেহেতু আমি আমার কিছু পরীক্ষাগুলি আবিষ্কার করেছি যা clock()প্রায় তত দ্রুত নয় যা আমি ভেবেছিলাম এটি।
মাকিং হাঁস

উত্তর:


83

লুপে বারবার ফাংশনটি চালানোর বিষয়ে অন্যেরা যা পোস্ট করেছে তা সঠিক।

লিনাক্সের জন্য (এবং BSD) আপনি ঘড়ি_সেটটাইম () ব্যবহার করতে চান ।

#include <sys/time.h>

int main()
{
   timespec ts;
   // clock_gettime(CLOCK_MONOTONIC, &ts); // Works on FreeBSD
   clock_gettime(CLOCK_REALTIME, &ts); // Works on Linux
}

উইন্ডোজের জন্য আপনি ক্যোরি পারফরম্যান্স কাউন্টার ব্যবহার করতে চান । এবং এখানে কিউপিসিতে আরও রয়েছে

স্পষ্টতই কিছু চিপসেটগুলিতে কিউপিসি নিয়ে একটি পরিচিত সমস্যা রয়েছে, তাই আপনি নিশ্চিত করতে পারেন যে আপনার কাছে এই চিপসেটটি নেই। অতিরিক্তভাবে কিছু ডুয়াল কোর এএমডিও সমস্যার কারণ হতে পারে । সেব্বির দ্বিতীয় পোস্টটি দেখুন, যেখানে তিনি বলেছেন:

কোয়েরি পারফরম্যান্স কাউন্টার () এবং কোয়েরি পারফরম্যান্স ফ্রিকোয়েন্সি () কিছুটা ভাল রেজোলিউশনের প্রস্তাব দেয় তবে বিভিন্ন সমস্যা রয়েছে। উইন্ডোজ এক্সপির উদাহরণস্বরূপ, সমস্ত এএমডি অ্যাথলন এক্স 2 ডুয়াল কোর সিপিইউগুলি "এলোমেলোভাবে" পিসি ফেরত দেয় (পিসি কখনও কখনও কিছুটা পিছনে পিছনে যায়) যদি না আপনি বিশেষত এএমডি ডুয়াল কোর ড্রাইভার প্যাকেজটি সমস্যা সমাধানের জন্য ইনস্টল না করেন। আমরা অন্য কোনও দ্বৈত + মূল সিপিইউতে একই রকম সমস্যা (পি 4 ডুয়াল, পি 4 এইচটি, কোর 2 ডুয়াল, কোর 2 কোয়াড, ফেনোম কোয়াড) লক্ষ্য করেছি।

সম্পাদনা 2013/07/16:

দেখে মনে হচ্ছে যে কিছু পরিস্থিতিতে কিউপিসি এর কার্যকারিতা নিয়ে কিছু বিতর্ক রয়েছে যেমন http://msdn.microsoft.com/en-us/library/windows/desktop/ee417693(v=vs.85).aspx এ বলা হয়েছে

... কোয়েরি পারফরম্যান্স কাউন্টার এবং কোয়েরি পারফরম্যান্স ফ্রিকোয়েন্সি সাধারণত একাধিক প্রসেসরের জন্য সামঞ্জস্য করে, বায়োস বা ড্রাইভারগুলিতে বাগগুলি এই প্রথাগুলিকে বিভিন্ন প্রসেসরের থেকে থ্রেড অন্য প্রসেসরে নিয়ে যাওয়ার কারণে বিভিন্ন মান ফিরিয়ে আনতে পারে ...

তবে এই স্ট্যাকওভারফ্লো উত্তরটি https://stackoverflow.com/a/4588605/34329 বলে যে উইন এক্সপি সার্ভিস প্যাক 2-এর পরে কোনও এমএস ওএসে কিউপিসি সূক্ষ্মভাবে কাজ করা উচিত।

এই নিবন্ধটি দেখায় যে উইন্ডোজ 7 প্রসেসর (গুলি) এর একটি ইনভেরিয়েন্ট টিএসসি রয়েছে কিনা তা নির্ধারণ করতে পারে এবং যদি তা না করে তবে তারা কোনও বাহ্যিক টাইমারে ফিরে যায়। http://performancebydesign.blogspot.com/2012/03/high-resolution-clocks-and-timers-for.html প্রসেসরের জুড়ে সিনক্রোনাইজ করা এখনও একটি সমস্যা।

টাইমার সম্পর্কিত অন্যান্য সূক্ষ্ম পাঠ:

আরও বিশদ জন্য মন্তব্য দেখুন।


1
আমি টিএসসির ঘড়িটি পুরানো দ্বৈত Xeon পিসিতে দেখেছি, তবে C1 ক্লক র‌্যাম্পিং সক্ষম করে অ্যাথলন এক্স 2 এর মতো খারাপ নয়। সি 1 ক্লক র‌্যাম্পিংয়ের সাথে, এইচএলটি নির্দেশনা কার্যকর করা ঘড়িটি ধীর করে দেয়, অলস কোরগুলিতে টিএসসি সক্রিয় কোরের চেয়ে ধীরে ধীরে বৃদ্ধি পাবে।
bk1e

6
ক্লক_মোনটোনিক আমার লিনাক্সের যে সংস্করণগুলি উপলভ্য তা নিয়ে কাজ করে।
বার্নার্ড

1
@ বার্নার্ড - যেহেতু আমি শেষবার এটি দেখেছি সেটিকে অবশ্যই নতুনভাবে যুক্ত করা উচিত। সতর্ক থাকুন জন্য ধন্যবাদ।
শোক করুন

3
আসলে, CLOCK_MONOTONIC_RAWএনটিপি দ্বারা হার্ডওয়্যার সময় সামঞ্জস্য না করার জন্য আপনাকে যদি এটি উপলব্ধ থাকে তবে তা ব্যবহার করতে হবে।

হিসাবে এখানে আলোচনা, QPC সঠিক বাস্তবায়ন টিএসসি কাউন্টার ব্যবহার করবেন না, অন্তত যেখানে এটি অবিশ্বস্ত হিসেবে পরিচিত হয়: stackoverflow.com/q/510462/53974
Blaisorblade

69

এই নতুন উত্তরটিতে সি ++ 11 এর <chrono>সুবিধা ব্যবহার করা হয়েছে। যদিও অন্যান্য উত্তর রয়েছে যা কীভাবে ব্যবহার করতে <chrono>হয় তা দেখায়, তাদের মধ্যে কেউই এখানে অন্য উত্তরগুলির কয়েকটিতে উল্লিখিত সুবিধাটি কীভাবে ব্যবহার করতে <chrono>হয় তা দেখায় না RDTSC। তাই আমি ভাবলাম কীভাবে ব্যবহার করবেন তা দেখাতে হবে RDTSCসঙ্গে <chrono>। উপরন্তু আমি প্রমান করবে কিভাবে বুঝবেন আপনার দ্রুত মধ্যে সুইচ করতে পারেন ঘড়িতে পরীক্ষামূলক কোড templatize করতে পারেন যাতে RDTSCএবং আপনার সিস্টেম বিল্ট-ইন ঘড়িটি সুবিধা (যা সম্ভবত উপর ভিত্তি করে করা হবে clock(), clock_gettime()এবং / অথবা QueryPerformanceCounter

লক্ষ করুন যে RDTSCনির্দেশটি x86- নির্দিষ্ট। QueryPerformanceCounterশুধুমাত্র উইন্ডোজ। এবং clock_gettime()কেবল পসিক্স। নীচে আমি দুটি নতুন ঘড়ি পরিচয় করিয়ে দিচ্ছি: std::chrono::high_resolution_clockএবং std::chrono::system_clock, যদি আপনি সি ++ 11 ধরে নিতে পারেন তবে এখন ক্রস প্ল্যাটফর্ম।

প্রথমত, এখানে আপনি কীভাবে ইন্টেল rdtscসমাবেশ নির্দেশাবলীর বাইরে একটি C ++ 11- সামঞ্জস্যপূর্ণ ঘড়ি তৈরি করবেন । আমি এটি কল করব x::clock:

#include <chrono>

namespace x
{

struct clock
{
    typedef unsigned long long                 rep;
    typedef std::ratio<1, 2'800'000'000>       period; // My machine is 2.8 GHz
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<clock>     time_point;
    static const bool is_steady =              true;

    static time_point now() noexcept
    {
        unsigned lo, hi;
        asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
        return time_point(duration(static_cast<rep>(hi) << 32 | lo));
    }
};

}  // x

এই সমস্ত ঘড়িটি সিপিইউ চক্র গণনা করা এবং এটি স্বাক্ষরবিহীন 64৪-বিট পূর্ণসংখ্যায় সঞ্চয় করে। আপনার সংকলকটির জন্য আপনার বিধানসভা ভাষার সিনট্যাক্সটি সামলানো দরকার। অথবা আপনার সংকলক একটি অভ্যন্তরীণ প্রস্তাব দিতে পারে যার পরিবর্তে আপনি ব্যবহার করতে পারেন (যেমন now() {return __rdtsc();})।

একটি ঘড়ি তৈরি করতে আপনাকে এটিকে উপস্থাপনা (স্টোরেজ টাইপ) দিতে হবে। আপনার মেশিনটি বিভিন্ন পাওয়ার মোডে ঘড়ির গতি পরিবর্তন করতে পারে তার পরেও আপনাকে অবশ্যই ক্লক পিরিয়ড সরবরাহ করতে হবে which এবং এগুলি থেকে আপনি আপনার ঘড়ির "নেটিভ" সময়কাল এবং সময়সূত্রগুলি এই মৌলিক বিষয়গুলির ভিত্তিতে সহজেই সংজ্ঞায়িত করতে পারেন।

যদি আপনি যা করতে চান তা হ'ল ক্লক টিকের সংখ্যা আউটপুট করা হয় তবে আপনি ঘড়ির সময়কালের জন্য কোন নম্বর দিবেন তা আসলেই গুরুত্বপূর্ণ নয়। এই ধ্রুবকটি কেবলমাত্র খেলায় আসে যদি আপনি ঘড়ির টিকের সংখ্যাটিকে কিছু রিয়েল-টাইম ইউনিটে যেমন ন্যানোসেকেন্ডগুলিতে রূপান্তর করতে চান। এবং সেক্ষেত্রে আপনি যত বেশি ঘড়ির গতি সরবরাহ করতে সক্ষম হবেন তত বেশি সঠিক হ'ল ন্যানোসেকেন্ডে (মিলিসেকেন্ড, যাই হোক না কেন) রূপান্তর।

নীচে উদাহরণ কোড রয়েছে যা কীভাবে ব্যবহার করতে হয় তা দেখায় x::clock। আসলে আমি ঘড়িতে কোডটি টেম্পলেট করেছি যেহেতু আপনি ঠিক একই সিনট্যাক্সের সাহায্যে আপনি কীভাবে আরও অনেকগুলি ঘড়ি ব্যবহার করতে পারেন তা দেখাতে চাই। এই নির্দিষ্ট পরীক্ষাটি দেখায় যে আপনি যখন লুপের নীচে সময় কাটাতে চান তা চালানোর সময় লুপিং ওভারহেডটি কী:

#include <iostream>

template <class clock>
void
test_empty_loop()
{
    // Define real time units
    typedef std::chrono::duration<unsigned long long, std::pico> picoseconds;
    // or:
    // typedef std::chrono::nanoseconds nanoseconds;
    // Define double-based unit of clock tick
    typedef std::chrono::duration<double, typename clock::period> Cycle;
    using std::chrono::duration_cast;
    const int N = 100000000;
    // Do it
    auto t0 = clock::now();
    for (int j = 0; j < N; ++j)
        asm volatile("");
    auto t1 = clock::now();
    // Get the clock ticks per iteration
    auto ticks_per_iter = Cycle(t1-t0)/N;
    std::cout << ticks_per_iter.count() << " clock ticks per iteration\n";
    // Convert to real time units
    std::cout << duration_cast<picoseconds>(ticks_per_iter).count()
              << "ps per iteration\n";
}

এই কোডটি প্রথম কাজটি করে ফলাফলগুলি প্রদর্শন করার জন্য একটি "রিয়েল টাইম" ইউনিট তৈরি করে I've উদাহরণ হিসাবে একটি প্রাক-তৈরি std::chrono::nanosecondsইউনিট আমি ব্যবহার করতে পারতাম।

অন্য একটি উদাহরণ হিসাবে আমি পুনরাবৃত্তি প্রতি ঘড়ির চক্রের গড় সংখ্যা একটি ভাসমান বিন্দু হিসাবে মুদ্রণ করতে চাই, তাই আমি দ্বিগুণের ভিত্তিতে আরেকটি সময়কাল তৈরি করি, যেটির ঘড়ির টিকের মতো একই ইউনিট থাকে (কোডটিতে বলা Cycleহয়)।

লুপটি clock::now()উভয় পক্ষের কলগুলির সাথে সমাপ্ত হয়। আপনি যদি এই ফাংশন থেকে ফিরে আসা টাইপের নাম রাখতে চান তবে তা হ'ল:

typename clock::time_point t0 = clock::now();

( x::clockউদাহরণে যেমন স্পষ্টভাবে দেখানো হয়েছে , এবং এটি সিস্টেম-সরবরাহকৃত ঘড়িগুলির ক্ষেত্রেও সত্য)।

ভাসমান পয়েন্ট ক্লক টিকের ক্ষেত্রে একটি সময়কাল পেতে একজন কেবল দুটি সময় পয়েন্টকে বিয়োগ করে এবং প্রতি পুনরাবৃত্তির মান পেতে, সেই সময়কালকে পুনরাবৃত্তির সংখ্যার দ্বারা ভাগ করে।

count()সদস্য ফাংশনটি ব্যবহার করে আপনি যে কোনও সময়কালে গণনা পেতে পারেন । এটি অভ্যন্তরীণ উপস্থাপনা ফেরত দেয়। অবশেষে আমি std::chrono::duration_castসময়কালকে সময়কালে রূপান্তর করতে এবং এটি মুদ্রণ Cycleকরতে ব্যবহার করি picoseconds

এই কোডটি ব্যবহার করা সহজ:

int main()
{
    std::cout << "\nUsing rdtsc:\n";
    test_empty_loop<x::clock>();

    std::cout << "\nUsing std::chrono::high_resolution_clock:\n";
    test_empty_loop<std::chrono::high_resolution_clock>();

    std::cout << "\nUsing std::chrono::system_clock:\n";
    test_empty_loop<std::chrono::system_clock>();
}

উপরে আমি আমাদের বাড়ির তৈরি ব্যবহার করে পরীক্ষাটি করি x::clockএবং সিস্টেম-সরবরাহ করা দুটি ঘড়ি ব্যবহার করে সেই ফলাফলগুলি তুলনা করি: std::chrono::high_resolution_clockএবং std::chrono::system_clock। আমার জন্য এটি প্রিন্ট করে:

Using rdtsc:
1.72632 clock ticks per iteration
616ps per iteration

Using std::chrono::high_resolution_clock:
0.620105 clock ticks per iteration
620ps per iteration

Using std::chrono::system_clock:
0.00062457 clock ticks per iteration
624ps per iteration

এটি দেখায় যে এই ঘড়ির প্রত্যেকটির আলাদা আলাদা টিক পিরিয়ড রয়েছে, কারণ প্রতিটি ঘড়ির জন্য পুনরাবৃত্তির জন্য টিকগুলি সম্পূর্ণ আলাদা। যাইহোক যখন সময়ের একটি পরিচিত ইউনিটে রূপান্তরিত হয় (যেমন পিকোসেকেন্ডস), আমি প্রতিটি ঘড়ির জন্য প্রায় একই ফলাফল পাই (আপনার মাইলেজ আলাদা হতে পারে)।

আমার কোডটি কীভাবে "ম্যাজিক রূপান্তর ধ্রুবকগুলি" থেকে সম্পূর্ণ মুক্ত তা নোট করুন। প্রকৃতপক্ষে পুরো উদাহরণটিতে কেবল দুটি ম্যাজিক সংখ্যা রয়েছে:

  1. সংজ্ঞায়িত করতে আমার মেশিনের ঘড়ির গতি x::clock
  2. পরীক্ষা করার জন্য পুনরাবৃত্তির সংখ্যা। যদি এই সংখ্যাটি পরিবর্তন করে আপনার ফলাফলগুলি ব্যাপকভাবে পরিবর্তিত হয়, তবে সম্ভবত আপনার পুনরাবৃত্তির সংখ্যা আরও বেশি হওয়া উচিত, বা পরীক্ষার সময় আপনার কম্পিউটারটি প্রতিদ্বন্দ্বী প্রক্রিয়াগুলি খালি করা উচিত।

5
"আরডিটিএসসি কেবলমাত্র ইন্টেল-কেবল", আপনি সত্যই x86 আর্কিটেকচার এবং ডেরিভেটিভসের কথা উল্লেখ করছেন, তাই না? এএমডি, সিরিক্স, ট্রান্সমিটা x86 চিপের নির্দেশনা রয়েছে এবং ইন্টেল আরআইএসসি এবং এআরএম প্রসেসরগুলি নেই।
বেন ভয়েগট

1
@ বেনভয়েট: +1 হ্যাঁ, আপনার সংশোধনটি বেশ সঠিক, আপনাকে ধন্যবাদ।
হাওয়ার্ড হিন্যান্ট

1
সিপিইউ থ্রোটলিং কীভাবে এটি প্রভাব ফেলবে? সিপিইউ লোডের ভিত্তিতে কি ঘড়ির গতি পরিবর্তন হয় না?
তেজস কালে

@ তেজসকালে: "ঘড়ি তৈরির জন্য আপনি ..." দিয়ে শুরু করে টানা দুটি অনুচ্ছেদে উত্তরে এটি বর্ণিত হয়েছে। সাধারণত টাইমিং কোড কাজ পরিমাপ করে না যা কোন থ্রেডকে ব্লক করে (তবে এটি পারে)। এবং তাই সাধারণত আপনার সিপিইউ শ্বাসরোধ করবে না। তবে আপনি যদি ঘুম, মিটেক্স লক, শর্ত_ভরিবর্তনীয় অপেক্ষা, ইত্যাদি জড়িত কোড পরিমাপ করছেন তবে rdtscঘড়ির অন্য ইউনিটগুলিতে ভুল রূপান্তর হওয়ার সম্ভাবনা রয়েছে। আপনার পরিমাপগুলি সেট আপ করা ভাল ধারণা যাতে আপনি সহজেই ঘড়িগুলি পরিবর্তন এবং তুলনা করতে পারেন (এই উত্তরে দেখানো হয়েছে)।
হাওয়ার্ড হিন্যান্ট

27

নির্ভুলতার সেই স্তরের সাথে, সিপিইউ টিকের মাধ্যমে সিস্টেম কলকে ক্লক () এর চেয়ে যুক্তি দেওয়া ভাল । এবং ভুলে যাবেন না যে যদি কোনও নির্দেশিকা কার্যকর করতে একাধিক ন্যানোসেকেন্ড লাগে ... ন্যানোসেকেন্ডের যথাযথতা থাকা বেশ অসম্ভব।

তবুও, এরকম কিছু একটা শুরু:

সিপিইউ শেষ শুরু হওয়ার পর থেকে পাস করা 80x86 সিপিইউ ক্লক টিক্সের সংখ্যার পুনরুদ্ধারের আসল কোডটি এখানে। এটি পেন্টিয়াম এবং তারপরে (386/486 সমর্থিত নয়) কাজ করবে। এই কোডটি আসলে এমএস ভিজ্যুয়াল সি ++ নির্দিষ্ট, তবে যতক্ষণ না এটি ইনলাইন অ্যাসেমব্লিকে সমর্থন করে ততক্ষণ খুব সহজেই অন্য যে কোনও কিছুতে পোর্ট করা যায়।

inline __int64 GetCpuClocks()
{

    // Counter
    struct { int32 low, high; } counter;

    // Use RDTSC instruction to get clocks count
    __asm push EAX
    __asm push EDX
    __asm __emit 0fh __asm __emit 031h // RDTSC
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    // Return result
    return *(__int64 *)(&counter);

}

এই ফাংশনটি অত্যন্ত দ্রুত হওয়ার সুবিধাও রয়েছে - এটি সম্পাদন করতে সাধারণত 50 সিপিইউ চক্রের বেশি লাগে না।

সময় চিত্রগুলি ব্যবহার :
যদি আপনাকে ঘড়ির গণনাগুলি সত্যিকারের অতিবাহিত সময়ের মধ্যে অনুবাদ করতে হয়, তবে ফলাফলগুলি আপনার চিপের ঘড়ির গতি দ্বারা ভাগ করুন। মনে রাখবেন যে "রেটযুক্ত" গিগাহার্টজ আপনার চিপের আসল গতি থেকে কিছুটা আলাদা হতে পারে। আপনার চিপের সত্যিকারের গতি পরীক্ষা করতে আপনি বেশ কয়েকটি খুব ভাল ইউটিলিটি বা উইন 32 কল, কোয়েরি পারফরম্যান্স ফ্রিকোয়েন্সি () ব্যবহার করতে পারেন।


তথ্যের জন্য ধন্যবাদ, এটি দরকারী। সময়টি গণনা করার জন্য আমি সিপিইউ চক্রের কথা ভাবি নি, আমি মনে করি এটি খুব ভাল পয়েন্ট :-)
3

4
কোয়েরি পারফরম্যান্স ফ্রিকোয়েন্সি () ব্যবহার করে টিএসসি গণনাগুলিকে অতিবাহিত সময়ে রূপান্তর করতে কাজ নাও করতে পারে। কোয়েরি পারফরম্যান্স কাউন্টার () উপলভ্য হলে ভিস্তার উপর এইচপিইটি (হাই প্রিসিশন ইভেন্ট টাইমার) ব্যবহার করে। এটি এসিপিআই পাওয়ার ম্যানেজমেন্ট টাইমার ব্যবহার করে যদি ব্যবহারকারী বুটআইএনআই / ইউএসইপিএমটিআইএমআর যুক্ত করে।
bk1e

23

এটি সঠিকভাবে করতে আপনি দুটি উপায়ের একটি ব্যবহার করতে পারেন, হয় যান RDTSCবা সাথে যান clock_gettime()। দ্বিতীয়টি প্রায় 2 গুণ দ্রুত এবং সঠিক পরম সময় দেওয়ার সুবিধা রয়েছে। মনে রাখবেন RDTSCসঠিকভাবে কাজ করার জন্য আপনাকে এটি নির্দেশিত হিসাবে ব্যবহার করতে হবে (এই পৃষ্ঠায় অন্যান্য মন্তব্যে ত্রুটি রয়েছে এবং কিছু প্রসেসরের ভুল সময় নির্ধারণ করতে পারে)

inline uint64_t rdtsc()
{
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx" );
    return (uint64_t)hi << 32 | lo;
}

এবং ক্লক_জেটটাইমের জন্য: (আমি নির্বিচারে মাইক্রোসেকেন্ড রেজোলিউশনটি বেছে নিয়েছি)

#include <time.h>
#include <sys/timeb.h>
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 mcs resolution (divide by 1M to get time_t)
uint64_t ClockGetTime()
{
    timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return (uint64_t)ts.tv_sec * 1000000LL + (uint64_t)ts.tv_nsec / 1000LL;
}

সময় এবং মান উত্পাদিত:

Absolute values:
rdtsc           = 4571567254267600
clock_gettime   = 1278605535506855

Processing time: (10000000 runs)
rdtsc           = 2292547353
clock_gettime   = 1031119636

22

আমি পছন্দসই ফলাফল পেতে নিম্নলিখিত ব্যবহার করছি:

#include <time.h>
#include <iostream>
using namespace std;

int main (int argc, char** argv)
{
    // reset the clock
    timespec tS;
    tS.tv_sec = 0;
    tS.tv_nsec = 0;
    clock_settime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    ...
    ... <code to check for the time to be put here>
    ...
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tS);
    cout << "Time taken is: " << tS.tv_sec << " " << tS.tv_nsec << endl;

    return 0;
}

2
আমি ডাউনভোটেড কারণ এই কোডটি প্রয়োগ করার চেষ্টা করার সময় আমাকে প্রথমে গুগল করতে হয়েছিল কেন টাইমস্পেক সংজ্ঞায়িত করা হয়নি। তারপরে আমাকে হোয়াট পসিক্স গুগল করতে হয়েছিল ... এবং তাই আমি এটি বুঝতে পেরেছিলাম, এই কোডটি উইন্ডোজ ব্যবহারকারীদের জন্য প্রাসঙ্গিক নয় যারা স্ট্যান্ডার্ড লাইব্রেরিটির সাথে কী আঁকেন।
ড্যানিয়েল কাটজ

8

সি ++ 11 এর জন্য এখানে একটি সাধারণ মোড়ক দেওয়া আছে:

#include <iostream>
#include <chrono>

class Timer
{
public:
    Timer() : beg_(clock_::now()) {}
    void reset() { beg_ = clock_::now(); }
    double elapsed() const {
        return std::chrono::duration_cast<second_>
            (clock_::now() - beg_).count(); }

private:
    typedef std::chrono::high_resolution_clock clock_;
    typedef std::chrono::duration<double, std::ratio<1> > second_;
    std::chrono::time_point<clock_> beg_;
};

অথবা সি ++ 03 এর জন্য * নিক্সে,

class Timer
{
public:
    Timer() { clock_gettime(CLOCK_REALTIME, &beg_); }

    double elapsed() {
        clock_gettime(CLOCK_REALTIME, &end_);
        return end_.tv_sec - beg_.tv_sec +
            (end_.tv_nsec - beg_.tv_nsec) / 1000000000.;
    }

    void reset() { clock_gettime(CLOCK_REALTIME, &beg_); }

private:
    timespec beg_, end_;
};

ব্যবহারের উদাহরণ:

int main()
{
    Timer tmr;
    double t = tmr.elapsed();
    std::cout << t << std::endl;

    tmr.reset();
    t = tmr.elapsed();
    std::cout << t << std::endl;
    return 0;
}

Https://gist.github.com/gongzhitaao/7062087 থেকে


5

সাধারণভাবে, কোনও ফাংশন কল করতে কত সময় লাগে তার সময়সীমা নির্ধারণের জন্য, আপনি এটি একবারের চেয়ে আরও অনেক বার করতে চান। যদি আপনি কেবল একবার আপনার ফাংশনটি কল করেন এবং এটি চালাতে খুব অল্প সময় নেয় তবে আপনার কাছে এখনও টাইমার ফাংশনগুলি কল করার ওভারহেড থাকে এবং আপনি জানেন না যে এটি কতটা সময় নেয়।

উদাহরণস্বরূপ, যদি আপনি অনুমান করেন যে আপনার ফাংশনটি চালাতে 800 এনএস লাগতে পারে তবে এটি দশ মিলিয়ন বার লুপে কল করুন (এটি প্রায় 8 সেকেন্ড সময় নেবে)। প্রতি কলে সময় পেতে মোট সময়কে দশ মিলিয়ন দিয়ে ভাগ করুন।


প্রকৃতপক্ষে, আমি একটি বিশেষ কলের জন্য এপিআইয়ের সম্পাদনা পাওয়ার চেষ্টা করছি। প্রতিটি রানের জন্য, এটি আলাদা সময় দিতে পারে, এটি পারফরম্যান্সের উন্নতির জন্য আমি যে গ্রাফটি তৈরি করবো তার প্রভাব ফেলতে পারে ... তাই ন্যানো সেকেন্ডে সময়। তবে হ্যাঁ, এটি একটি দুর্দান্ত ধারণা, এটি বিবেচনা করবে।
গ্যাগনিট

5

আপনি x86 প্রসেসরের অধীনে চলছে জিসিসি সহ নিম্নলিখিত ফাংশনটি ব্যবহার করতে পারেন:

unsigned long long rdtsc()
{
  #define rdtsc(low, high) \
         __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))

  unsigned int low, high;
  rdtsc(low, high);
  return ((ulonglong)high << 32) | low;
}

ডিজিটাল মঙ্গল সি ++ সহ:

unsigned long long rdtsc()
{
   _asm
   {
        rdtsc
   }
}

যা চিপটিতে উচ্চ পারফরম্যান্স টাইমার পড়ে। প্রোফাইলিং করার সময় আমি এটি ব্যবহার করি।


2
এটি দরকারী, আমি পরীক্ষার জন্য একটি অ্যাপল ম্যাক ব্যবহার করছি প্রসেসরটি x86 কিনা তা আমি যাচাই করব ... ধন্যবাদ :-)
গ্যাজনীট

1
উচ্চ এবং নিম্নের জন্য ব্যবহারকারীকে কী মান দেওয়ার কথা রয়েছে? আপনি কেন কোনও ফাংশনের শরীরে ম্যাক্রো সংজ্ঞায়িত করেন? এছাড়াও, উলংলং সম্ভবত স্বাক্ষরযুক্ত দীর্ঘ দীর্ঘ টাইপ করতে চাইলেও এটি কোনও প্রকারের আদর্শ নয়। আমি এটি ব্যবহার করতে চাই তবে কীভাবে নিশ্চিত তা আমি নিশ্চিত নই;)
জোসেফ গারভিন

1
লাইনাক্সের অধীনে স্বাক্ষরযুক্ত দীর্ঘ সময় ব্যবহার করা সঠিক জিনিস নয়। আপনি পরিবর্তে ইন্ট ব্যবহার বিবেচনা করতে চাইতে পারেন যেহেতু দীর্ঘ-দীর্ঘ উভয়ই 64৪-বিট লিনাক্সের 64৪-বিট।
মারিয়াস

3
টিএসসির কাউন্টারটি আজকাল প্রায়শই অবিশ্বাস্য:
ব্লেসরব্ল্যাড

1
@ মারিয়াস: আমি unsigned intঅভ্যন্তরীণ ধরণ হিসাবে আপনার মন্তব্যটি প্রয়োগ করেছি implemented
ব্লেসরব্ল্যাড

3

আপনার যদি সাবসেকেন্ড যথার্থতা প্রয়োজন, আপনাকে সিস্টেম-নির্দিষ্ট এক্সটেনশনগুলি ব্যবহার করতে হবে এবং অপারেটিং সিস্টেমের জন্য ডকুমেন্টেশন দিয়ে পরীক্ষা করতে হবে। পসিক্স গেটটাইমডে মাইক্রোসেকেন্ডগুলিতে সমর্থন করে তবে কম্পিউটারগুলি 1GHz এর বেশি ফ্রিকোয়েন্সি না থাকায় এর থেকে আরও সুনির্দিষ্ট কিছু নেই।

আপনি যদি বুস্ট ব্যবহার করে থাকেন তবে আপনি বুস্ট :: পোস্টিক্স_টাইম পরীক্ষা করতে পারেন ।


কোডটি পোর্টেবল রাখতে চান, বুস্ট লাইব্রেরি দেখতে পাবেন এবং আমি কোড দিয়ে এটি বান্ডেল করতে পারব কিনা তা পরীক্ষা করে দেখুন। ধন্যবাদ :-)
গ্যাগনিট

3

আমি এখানে বোরল্যান্ড কোড ব্যবহার করছি টিআইহুন্ড কোডটি আমাকে কিছু সময় নেতিবাচক নম্বর দেয় তবে টাইমিং মোটামুটি ভাল।

#include <dos.h>

void main() 
{
struct  time t;
int Hour,Min,Sec,Hun;
gettime(&t);
Hour=t.ti_hour;
Min=t.ti_min;
Sec=t.ti_sec;
Hun=t.ti_hund;
printf("Start time is: %2d:%02d:%02d.%02d\n",
   t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund);
....
your code to time
...

// read the time here remove Hours and min if the time is in sec

gettime(&t);
printf("\nTid Hour:%d Min:%d Sec:%d  Hundreds:%d\n",t.ti_hour-Hour,
                             t.ti_min-Min,t.ti_sec-Sec,t.ti_hund-Hun);
printf("\n\nAlt Ferdig Press a Key\n\n");
getch();
} // end main

3

ব্রোক অ্যাডামসের পদ্ধতিটি ব্যবহার করে, একটি সাধারণ ক্লাস সহ:

int get_cpu_ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}

__int64 get_cpu_clocks()
{
    struct { int32 low, high; } counter;

    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX

    return *(__int64 *)(&counter);
}

class cbench
{
public:
    cbench(const char *desc_in) 
         : desc(strdup(desc_in)), start(get_cpu_clocks()) { }
    ~cbench()
    {
        printf("%s took: %.4f ms\n", desc, (float)(get_cpu_clocks()-start)/get_cpu_ticks());
        if(desc) free(desc);
    }
private:
    char *desc;
    __int64 start;
};

ব্যবহারের উদাহরণ:

int main()
{
    {
        cbench c("test");
        ... code ...
    }
    return 0;
}

ফলাফল:

পরীক্ষা নেওয়া হয়েছে: 0.0002 এমএস

কিছু ফাংশন কল ওভারহেড আছে, কিন্তু দ্রুত যথেষ্ট চেয়ে বেশি হওয়া উচিত :)


3

আপনি এম্বেডড প্রোফাইলার (উইন্ডোজ এবং লিনাক্সের জন্য নিখরচায়) ব্যবহার করতে পারেন যা একটি মাল্টিপ্লাটফর্ম টাইমার (একটি প্রসেসরের চক্র গণনায়) এর ইন্টারফেস রয়েছে এবং আপনাকে প্রতি সেকেন্ডে বেশ কয়েকটি চক্র দিতে পারে:

EProfilerTimer timer;
timer.Start();

... // Your code here

const uint64_t number_of_elapsed_cycles = timer.Stop();
const uint64_t nano_seconds_elapsed =
    mumber_of_elapsed_cycles / (double) timer.GetCyclesPerSecond() * 1000000000;

সময়ে সময়ে চক্র গণনার পুনঃ গণনন সম্ভবত আধুনিক প্রসেসরের সাথে একটি বিপজ্জনক অপারেশন যেখানে সিপিইউ ফ্রিকোয়েন্সি গতিশীল পরিবর্তন করা যেতে পারে। সুতরাং রূপান্তরিত সময়গুলি সঠিক কিনা তা নিশ্চিত হওয়ার জন্য, প্রোফাইলিংয়ের আগে প্রসেসরের ফ্রিকোয়েন্সি ঠিক করা প্রয়োজন।


2

যদি এটি লিনাক্সের জন্য হয় তবে আমি "গেটটাইমডে" ফাংশনটি ব্যবহার করছি, যা এমন এক স্ট্রাক্ট দেয় যা যুগের পর থেকে সেকেন্ড এবং মাইক্রোসেকেন্ড দেয়। তারপরে সময় পার্থক্য পেতে আপনি দুটি বিয়োগ করতে টাইমারসব ব্যবহার করতে পারেন, এবং সময়ের যে নির্ভুলতা চান তা এটিকে রূপান্তর করতে পারেন। যাইহোক, আপনি ন্যানোসেকেন্ডগুলি নির্দিষ্ট করুন, এবং এটির মতো দেখায় যে ফাংশন ক্লক_জেটটাইম () আপনি যা সন্ধান করছেন। এটি সেকেন্ড এবং ন্যানোসেকেন্ডগুলিকে আপনি যে কাঠামোর মধ্যে দিয়ে গেছেন তাতে সময় দেয়।


ঘড়ি_কালীন সময় () আপাতত কৌশলটি করা উচিত। আমার উদ্দেশ্যে একই ব্যবহার করার চেষ্টা করবে ...
gagneet

2

তুমি এটা সম্পর্কে কী ভাব:

    int iceu_system_GetTimeNow(long long int *res)
    {
      static struct timespec buffer;
      // 
    #ifdef __CYGWIN__
      if (clock_gettime(CLOCK_REALTIME, &buffer))
        return 1;
    #else
      if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &buffer))
        return 1;
    #endif
      *res=(long long int)buffer.tv_sec * 1000000000LL + (long long int)buffer.tv_nsec;
      return 0;
    }

2

এখানে একটি দুর্দান্ত বুস্ট টাইমার রয়েছে যা ভালভাবে কাজ করে:

//Stopwatch.hpp

#ifndef STOPWATCH_HPP
#define STOPWATCH_HPP

//Boost
#include <boost/chrono.hpp>
//Std
#include <cstdint>

class Stopwatch
{
public:
    Stopwatch();
    virtual         ~Stopwatch();
    void            Restart();
    std::uint64_t   Get_elapsed_ns();
    std::uint64_t   Get_elapsed_us();
    std::uint64_t   Get_elapsed_ms();
    std::uint64_t   Get_elapsed_s();
private:
    boost::chrono::high_resolution_clock::time_point _start_time;
};

#endif // STOPWATCH_HPP


//Stopwatch.cpp

#include "Stopwatch.hpp"

Stopwatch::Stopwatch():
    _start_time(boost::chrono::high_resolution_clock::now()) {}

Stopwatch::~Stopwatch() {}

void Stopwatch::Restart()
{
    _start_time = boost::chrono::high_resolution_clock::now();
}

std::uint64_t Stopwatch::Get_elapsed_ns()
{
    boost::chrono::nanoseconds nano_s = boost::chrono::duration_cast<boost::chrono::nanoseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(nano_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_us()
{
    boost::chrono::microseconds micro_s = boost::chrono::duration_cast<boost::chrono::microseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(micro_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_ms()
{
    boost::chrono::milliseconds milli_s = boost::chrono::duration_cast<boost::chrono::milliseconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(milli_s.count());
}

std::uint64_t Stopwatch::Get_elapsed_s()
{
    boost::chrono::seconds sec = boost::chrono::duration_cast<boost::chrono::seconds>(boost::chrono::high_resolution_clock::now() - _start_time);
    return static_cast<std::uint64_t>(sec.count());
}

2

নমনীয় কপি এবং পেস্ট-স্ট্রাক্ট + অলস ব্যবহার

যদি ধারণাটি এমন একটি নমনীয় কাঠামো থাকে যা আপনি দ্রুত পরীক্ষার জন্য ব্যবহার করতে পারেন তবে আমি পরামর্শ দিচ্ছি যে আপনি ঠিক আপনার সি ++ ফাইলে যে কোনও জায়গায় অনুলিপি করে পেস্ট করুন #include। এটিই একমাত্র উদাহরণ যেখানে আমি অলম্যান-স্টাইল বিন্যাসকে ত্যাগ করি।

আপনি সহজেই কাঠামোর প্রথম লাইনে নির্ভুলতা সামঞ্জস্য করতে পারেন। সম্ভাব্য মান হল: nanoseconds, microseconds, milliseconds, seconds, minutes, অথবা hours

#include <chrono>
struct MeasureTime
{
    using precision = std::chrono::microseconds;
    std::vector<std::chrono::steady_clock::time_point> times;
    std::chrono::steady_clock::time_point oneLast;
    void p() {
        std::cout << "Mark " 
                << times.size()/2
                << ": " 
                << std::chrono::duration_cast<precision>(times.back() - oneLast).count() 
                << std::endl;
    }
    void m() {
        oneLast = times.back();
        times.push_back(std::chrono::steady_clock::now());
    }
    void t() {
        m();
        p();
        m();
    }
    MeasureTime() {
        times.push_back(std::chrono::steady_clock::now());
    }
};

ব্যবহার

MeasureTime m; // first time is already in memory
doFnc1();
m.t(); // Mark 1: next time, and print difference with previous mark
doFnc2();
m.t(); // Mark 2: next time, and print difference with previous mark
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.t(); // prints 'Mark 3: 123123' etc...

স্ট্যান্ডার্ড আউটপুট ফলাফল

Mark 1: 123
Mark 2: 32
Mark 3: 433234

আপনি যদি মৃত্যুদন্ড কার্যকর করার পরে সংক্ষিপ্ত বিবরণ চান

আপনি যদি পরে প্রতিবেদনটি চান তবে কারণ উদাহরণস্বরূপ আপনার কোড এর মধ্যে স্ট্যান্ডার্ড আউটপুটও লিখবে। তারপরে স্ট্রাক্টে (নিচে মেজারটাইম () এর ঠিক আগে) নিম্নলিখিত ফাংশনটি যুক্ত করুন:

void s() { // summary
    int i = 0;
    std::chrono::steady_clock::time_point tprev;
    for(auto tcur : times)
    {
        if(i > 0)
        {
            std::cout << "Mark " << i << ": "
                    << std::chrono::duration_cast<precision>(tprev - tcur).count()
                    << std::endl;
        }
        tprev = tcur;
        ++i;
    }
}

সুতরাং আপনি কেবল ব্যবহার করতে পারেন:

MeasureTime m;
doFnc1();
m.m();
doFnc2();
m.m();
doStuff = doMoreStuff();
andDoItAgain = doStuff.aoeuaoeu();
m.m();
m.s();

যা আগের মতো সমস্ত চিহ্নের তালিকা তৈরি করবে, তবে অন্য কোডটি কার্যকর করার পরে। মনে রাখবেন যে আপনার m.s()এবং উভয় ব্যবহার করা উচিত নয় m.t()


উবুন্টু 16.04 এ ওপেনএমপি নিয়ে পুরোপুরি কাজ করে। অনেক অনেক ধন্যবাদ, এটি সেরা উত্তর আইএমও করা উচিত!
orহোর এমও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.