সি ++ তে কোনও কোড স্নিপেটের কার্যকর করার সময় গণনা কিভাবে করবেন


121

আমাকে সি ++ কোড স্নিপেটের সেকেন্ডে নির্ধারণের সময় গণনা করতে হবে। এটি অবশ্যই উইন্ডোজ বা ইউনিক্স মেশিনে কাজ করবে।

এটি করার জন্য আমি নীচের কোডটি ব্যবহার করি। (আগে আমদানি)

clock_t startTime = clock();
// some code here
// to compute its execution duration in runtime
cout << double( clock() - startTime ) / (double)CLOCKS_PER_SEC<< " seconds." << endl;

তবে ছোট ইনপুট বা সংক্ষিপ্ত বিবৃতি যেমন a = a + 1 এর জন্য, আমি "0 সেকেন্ড" ফলাফল পেয়েছি। আমি মনে করি এটি অবশ্যই 0.0000001 সেকেন্ডের মতো কিছু বা এর মতো কোনও কিছু।

আমার মনে System.nanoTime()আছে জাভা এই ক্ষেত্রে বেশ ভাল কাজ করে। তবে আমি clock()সি ++ এর ফাংশন থেকে একই সঠিক কার্যকারিতাটি পেতে পারি না ।

আপনার কি সমাধান আছে?


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

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

হ্যাঁ আমি এটিকে কয়েকবার চালিয়েছি এবং ফলাফলগুলি বের করে আছি।
আহমেটবি - গুগল

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

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

উত্তর:


115

আমি লিখেছি এই ফাংশন আপনি ব্যবহার করতে পারেন। আপনি কল করেছেন GetTimeMs64()এবং এটি সিস্টেম ঘড়ি ব্যবহার করে ইউনিক্সের সূচনাকালীন থেকে বিভক্ত মিলিসেকেন্ডগুলির সংখ্যা ফিরে আসে - time(NULL)মিলিসেকেন্ড বাদে ঠিক তেমন।

এটি উইন্ডো এবং লিনাক্স উভয় ক্ষেত্রেই কাজ করে; এটা থ্রেড নিরাপদ।

নোট করুন যে গ্রানুলারিটি উইন্ডোতে 15 এমএস; লিনাক্সে এটি বাস্তবায়ন নির্ভর, তবে এটি সাধারণত 15 এমএসও হয়।

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#include <ctime>
#endif

/* Remove if already defined */
typedef long long int64; typedef unsigned long long uint64;

/* Returns the amount of milliseconds elapsed since the UNIX epoch. Works on both
 * windows and linux. */

uint64 GetTimeMs64()
{
#ifdef _WIN32
 /* Windows */
 FILETIME ft;
 LARGE_INTEGER li;

 /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
  * to a LARGE_INTEGER structure. */
 GetSystemTimeAsFileTime(&ft);
 li.LowPart = ft.dwLowDateTime;
 li.HighPart = ft.dwHighDateTime;

 uint64 ret = li.QuadPart;
 ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
 ret /= 10000; /* From 100 nano seconds (10^-7) to 1 millisecond (10^-3) intervals */

 return ret;
#else
 /* Linux */
 struct timeval tv;

 gettimeofday(&tv, NULL);

 uint64 ret = tv.tv_usec;
 /* Convert from micro seconds (10^-6) to milliseconds (10^-3) */
 ret /= 1000;

 /* Adds the seconds (10^0) after converting them to milliseconds (10^-3) */
 ret += (tv.tv_sec * 1000);

 return ret;
#endif
}

1
ভবিষ্যতের রেফারেন্সের জন্য: আমি এটিকে কেবল একটি হেডার ফাইলের মধ্যে ফেলে দিয়েছি এবং এটি ব্যবহার করি। এটা পেয়ে খুশি।
ড্যানিয়েল হ্যান্ডোজো

1
আমি বিশ্বাস করি যে gettimeofdayসিস্টেমের ঘড়িটি পরিবর্তিত হলে পদ্ধতিটি একটি অযৌক্তিক ফলাফল দিতে পারে। এটি আপনার যদি সমস্যা হয়ে থাকে তবে আপনি clock_gettimeপরিবর্তে এটি দেখতে চাইতে পারেন ।
আজমিসভ

উইন্ডোজের এই পদ্ধতির কি কোনও সুবিধা আছে GetTickCount?
মাইক্রোভাইরাস

ব্যবহার করে সংকলন করে নাgcc -std=c99
Assimarter

@ মাইক্রোভাইরাস: হ্যাঁ, GetTickCountসিস্টেমটি শুরু হওয়ার পর থেকে সময় অতিবাহিত হয়েছে, যখন আমার ফাংশনটি ইউনিক্স যুগের সময় থেকে ফিরে আসে যার অর্থ আপনি এটি তারিখ এবং সময় ব্যবহার করতে পারবেন। আপনি যদি কেবলমাত্র দুটি ইভেন্টের মধ্যে সময় কাটাতে আগ্রহী হন তবে খনি এখনও আরও ভাল পছন্দ কারণ এটি কোনও পূর্ববর্তী 64; গেটটিকাউন্ট একটি অন্তর্নিহিত every
থমাস বনিনি

43

আমার আরও একটি কার্যকারী উদাহরণ রয়েছে যা মাইক্রোসেকেন্ডগুলি ব্যবহার করে (ইউনিক্স, পসিক্স, ইত্যাদি)।

    #include <sys/time.h>
    typedef unsigned long long timestamp_t;

    static timestamp_t
    get_timestamp ()
    {
      struct timeval now;
      gettimeofday (&now, NULL);
      return  now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
    }

    ...
    timestamp_t t0 = get_timestamp();
    // Process
    timestamp_t t1 = get_timestamp();

    double secs = (t1 - t0) / 1000000.0L;

এখানে ফাইলটি এখানে কোড করা হয়েছে:

https://github.com/arhuaco/junkcode/blob/master/emqbit-bench/bench.c


5
#include <sys/time.h>আপনার উদাহরণের সূচনাতে আপনার যুক্ত করা উচিত ।
নিকাস

40

এখানে সি ++ 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 এর জন্য * নিক্সে

#include <iostream>
#include <ctime>

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 থেকে


আমি আপনার সি ++ 11 সমাধানের মাধ্যমে এই ত্রুটিটি /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version GLIBCXX_3.4.19 not found (required by ../cpu_2d/g500)
পাচ্ছি

@ জুলিয়ানোমরা কি প্ল্যাটফর্ম ব্যবহার করছেন? আপনি কি libstdc ++ গ্রন্থাগার এবং জি ++ ইনস্টল করেছেন?
gongzhitaao

এটি লিনাক্স উবুন্টু এর একটি স্লর্ম গ্রিড just আমি লিঙ্কারের শেষে -static-libstdc ++ যুক্ত করেছি। @ Gongzhitaao
ইউজার9869932

18
#include <boost/progress.hpp>

using namespace boost;

int main (int argc, const char * argv[])
{
  progress_timer timer;

  // do stuff, preferably in a 100x loop to make it take longer.

  return 0;
}

যখন progress_timerসুযোগের বাইরে চলে যায় তখন এটি তৈরির সময় থেকে সময় কেটে যায়।

আপডেট : এখানে বুস্ট ছাড়াই কাজ করে এমন একটি সংস্করণ রয়েছে (ম্যাকোস / আইওএস-এ পরীক্ষিত):

#include <chrono>
#include <string>
#include <iostream>
#include <math.h>
#include <unistd.h>

class NLTimerScoped {
private:
    const std::chrono::steady_clock::time_point start;
    const std::string name;

public:
    NLTimerScoped( const std::string & name ) : name( name ), start( std::chrono::steady_clock::now() ) {
    }


    ~NLTimerScoped() {
        const auto end(std::chrono::steady_clock::now());
        const auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>( end - start ).count();

        std::cout << name << " duration: " << duration_ms << "ms" << std::endl;
    }

};

int main(int argc, const char * argv[]) {

    {
        NLTimerScoped timer( "sin sum" );

        float a = 0.0f;

        for ( int i=0; i < 1000000; i++ ) {
            a += sin( (float) i / 100 );
        }

        std::cout << "sin sum = " << a << std::endl;
    }



    {
        NLTimerScoped timer( "sleep( 4 )" );

        sleep( 4 );
    }



    return 0;
}

2
এটি কাজ করে, তবে নোট করুন যে অগ্রগতি_টিটিমার অবমূল্যায়ন করা হয়েছে (1.50 বৃদ্ধির কিছু আগে) - অটো_সিপিউ_টিমার আরও উপযুক্ত হতে পারে।
ডেভিডা

3
@ মেসস্কোয়াক হুম, অটো_সিপিইউ_টিমার বুস্ট সিস্টেমের লাইব্রেরিটি সংযুক্ত করা দরকার বলে মনে হচ্ছে, সুতরাং এটি এখন কেবল শিরোনাম সমাধান নয়। খুব খারাপ ... হঠাৎ করে অন্য বিকল্পগুলি আরও আবেদনময় করে তোলে।
টমাস অ্যান্ড্রেল

1
হ্যাঁ, এটি একটি ভাল পয়েন্ট, আপনি যদি ইতিমধ্যে বুস্টকে লিঙ্ক না করেন তবে এটির মূল্যটি এর চেয়ে বেশি সমস্যা। আপনি যদি ইতিমধ্যে করেন তবে এটি বেশ সুন্দরভাবে কাজ করে।
ডেভিডা

@ মেমোস্কাক হ্যাঁ, বা কিছু দ্রুত বেঞ্চমার্ক পরীক্ষার জন্য কেবল বুস্টের সেই পুরানো সংস্করণটি পান।
টমাস অ্যান্ড্রেল

@ TomasAndrle লিঙ্কটির আর অস্তিত্ব নেই।
ঝেং Qu

5

উইন্ডোজ কোয়েরি পারফরম্যান্স কাউন্টার () ফাংশন সরবরাহ করে এবং ইউনিক্সে গেটটাইম ডে () উভয় ফাংশন কমপক্ষে 1 মাইক্রো-সেকেন্ড পার্থক্য পরিমাপ করতে পারে।


তবে উইন্ডোজ এইচ ব্যবহার সীমাবদ্ধ। একই সংকলিত উত্সটি উইন্ডোজ এবং ইউনিক্স উভয় ক্ষেত্রেই চলতে হবে। এই সমস্যাটি কীভাবে পরিচালনা করবেন?
আহমেটবি - গুগল

2
তারপরে কিছু মোড়কের লাইব্রেরির জন্য দেখুন stackoverflow.com/questions/1487695/…
ক্যাপ্টেন কমিক

4
একই সংকলিত উত্স শোনায় আপনি উভয় সিস্টেমে একই বাইনারি চালাতে চান, যা মনে হয় না। যদি আপনি বোঝানো একই উৎস তারপর #ifdefঠিক হতে হবে (এবং এটি উত্তর আপনাকে স্বীকার করেছে থেকে বিচার করা হয়), এবং তারপর আমি সমস্যা দেখি না: #ifdef WIN32 #include <windows.h> ... #else ... #endif
কেবলমাত্র

3

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

(উপরের লিঙ্কটি একটি ফরাসি উইকিপিডিয়া পৃষ্ঠায় রয়েছে, তবে এতে সি ++ কোডের নমুনা রয়েছে, ইংরেজী সংস্করণটি এখানে রয়েছে )


2

আমি সিস্টেম থেকে সময় তথ্য পাওয়ার জন্য স্ট্যান্ডার্ড গ্রন্থাগার ফাংশন ব্যবহার করার পরামর্শ দিই।

আপনি যদি সূক্ষ্ম রেজোলিউশন চান তবে আরও কার্যকর করার পুনরাবৃত্তি করুন। প্রোগ্রামটি একবার চালানোর পরিবর্তে এবং নমুনা পাওয়ার পরিবর্তে এটি 1000 বার বা তার বেশি চালান।


2

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

আপনার টাইমার কলগুলি উপযুক্ত সিস্টেমের জন্য মোড়ানো। উইন্ডোজের জন্য, ক্যোয়ারি পারফরম্যান্স কাউন্টার বেশ দ্রুত এবং ব্যবহারে "নিরাপদ"।

আপনি যে কোনও আধুনিক এক্স 86 PC পিসিতেও "rdtsc" ব্যবহার করতে পারেন তবে কিছু মাল্টিকোর মেশিনে সমস্যা থাকতে পারে (কোর হপিং টাইমার পরিবর্তন করতে পারে) বা যদি আপনার কোনও ধরণের গতি-পদক্ষেপ চালু থাকে।


2

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

#include <iostream>
#include <tchar.h>
#include <windows.h>

int main()
{
constexpr int MAX_ITER{ 10000 };
constexpr __int64 us_per_hour{ 3600000000ull }; // 3.6e+09
constexpr __int64 us_per_min{ 60000000ull };
constexpr __int64 us_per_sec{ 1000000ull };
constexpr __int64 us_per_ms{ 1000ull };

// easy to work with
__int64 startTick, endTick, ticksPerSecond, totalTicks = 0ull;

QueryPerformanceFrequency((LARGE_INTEGER *)&ticksPerSecond);

for (int iter = 0; iter < MAX_ITER; ++iter) {// start looping
    QueryPerformanceCounter((LARGE_INTEGER *)&startTick); // Get start tick
    // code to be timed
    std::cout << "cur_tick = " << iter << "\n";
    QueryPerformanceCounter((LARGE_INTEGER *)&endTick); // Get end tick
    totalTicks += endTick - startTick; // accumulate time taken
}

// convert to elapsed microseconds
__int64 totalMicroSeconds =  (totalTicks * 1000000ull)/ ticksPerSecond;

__int64 hours = totalMicroSeconds / us_per_hour;
totalMicroSeconds %= us_per_hour;
__int64 minutes = totalMicroSeconds / us_per_min;
totalMicroSeconds %= us_per_min;
__int64 seconds = totalMicroSeconds / us_per_sec;
totalMicroSeconds %= us_per_sec;
__int64 milliseconds = totalMicroSeconds / us_per_ms;
totalMicroSeconds %= us_per_ms;


std::cout << "Total time: " << hours << "h ";
std::cout << minutes << "m " << seconds << "s " << milliseconds << "ms ";
std::cout << totalMicroSeconds << "us\n";

return 0;
}

2

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

ওএস-মুক্ত যাওয়ার একটি ভাল বিকল্প হ'ল বর্তমান থ্রেডের সান্নিধ্যকে 1 টি করে সেট করা এবং সর্বোচ্চটিকে অগ্রাধিকার দেওয়া। এই বিকল্পের ধারাবাহিক পর্যাপ্ত ফলাফল সরবরাহ করা উচিত।

এছাড়াও আপনি অপ্টিমাইজেশন যা ডিবাগ, যা গ্রাম ++ অথবা জিসিসি উপায়ে জন্য হস্তক্ষেপ করবে বন্ধ করা উচিত যোগ -Ogকমান্ড লাইন থেকে কোড প্রতিরোধ আউট অপ্টিমাইজ হওয়া থেকে পরীক্ষা করা হচ্ছে। -O0পতাকা, কারণ এটি অতিরিক্ত অপ্রয়োজনীয় ওভারহেড যা সময়জ্ঞান ফলাফলে অন্তর্ভুক্ত করা হবে প্রবর্তন, এইভাবে কোডের সুবিধানুযায়ী গতি বিকৃতি বোসের ব্যবহার করা উচিত নয়।

বিপরীতে, উভয়ই ধরে নিচ্ছেন যে আপনি "মৃত" কোড নির্মূলকরণের বিষয়টি চূড়ান্ত উত্পাদন তৈরিতে এবং উপেক্ষা করে ব্যবহার করেন -Ofast(বা খুব কমপক্ষে, -O3), -Ogখুব কম অপ্টিমাইজেশন সম্পাদন করে -Ofast; এইভাবে -Ogচূড়ান্ত পণ্যটিতে কোডের আসল গতির ভুল উপস্থাপন করতে পারে।

তদ্ব্যতীত, সমস্ত গতি পরীক্ষা (কিছুটা হলেও) মিথ্যাচার: চূড়ান্ত উত্পাদনের পণ্য সংকলিত -Ofastপ্রতিটি স্নিপেট / বিভাগ / কোডের কার্য বিচ্ছিন্ন নয়; পরিবর্তে, কোডের প্রতিটি স্নিপেট অবিচ্ছিন্নভাবে পরবর্তীটিতে প্রবাহিত হয়, এইভাবে সংকলকটি সমস্ত স্থান থেকে কোডের টুকরোগুলিকে একসাথে যুক্ত হতে, মার্জ করতে এবং অনুকূলিত করতে দেয়।

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

অসম্পূর্ণতা হ্রাস করতে পারে একটি আংশিক সমাধান মৃত কোড / লুপ নির্মূল প্রতিরোধের জন্য পরীক্ষায় জড়িত ভেরিয়েবল যোগ করার -Ofastসাথে গতি asm volatile("" :: "r"(var))পরীক্ষার জন্য ব্যবহার করছে।

উইন্ডোজ কম্পিউটারে স্কোয়ার রুট ফাংশনগুলি কীভাবে বেনমার্ক করবেন তার একটি উদাহরণ এখানে।

// set USE_ASM_TO_PREVENT_ELIMINATION  to 0 to prevent `asm volatile("" :: "r"(var))`
// set USE_ASM_TO_PREVENT_ELIMINATION  to 1 to enforce `asm volatile("" :: "r"(var))`
#define USE_ASM_TO_PREVENT_ELIMINATION 1

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <chrono>
#include <cmath>
#include <windows.h>
#include <intrin.h>
#pragma intrinsic(__rdtsc)
#include <cstdint>

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_;
};

unsigned int guess_sqrt32(register unsigned int n) {
    register unsigned int g = 0x8000;
    if(g*g > n) {
        g ^= 0x8000;
    }
    g |= 0x4000;
    if(g*g > n) {
        g ^= 0x4000;
    }
    g |= 0x2000;
    if(g*g > n) {
        g ^= 0x2000;
    }
    g |= 0x1000;
    if(g*g > n) {
        g ^= 0x1000;
    }
    g |= 0x0800;
    if(g*g > n) {
        g ^= 0x0800;
    }
    g |= 0x0400;
    if(g*g > n) {
        g ^= 0x0400;
    }
    g |= 0x0200;
    if(g*g > n) {
        g ^= 0x0200;
    }
    g |= 0x0100;
    if(g*g > n) {
        g ^= 0x0100;
    }
    g |= 0x0080;
    if(g*g > n) {
        g ^= 0x0080;
    }
    g |= 0x0040;
    if(g*g > n) {
        g ^= 0x0040;
    }
    g |= 0x0020;
    if(g*g > n) {
        g ^= 0x0020;
    }
    g |= 0x0010;
    if(g*g > n) {
        g ^= 0x0010;
    }
    g |= 0x0008;
    if(g*g > n) {
        g ^= 0x0008;
    }
    g |= 0x0004;
    if(g*g > n) {
        g ^= 0x0004;
    }
    g |= 0x0002;
    if(g*g > n) {
        g ^= 0x0002;
    }
    g |= 0x0001;
    if(g*g > n) {
        g ^= 0x0001;
    }
    return g;
}

unsigned int empty_function( unsigned int _input ) {
    return _input;
}

unsigned long long empty_ticks=0;
double empty_seconds=0;
Timer my_time;

template<unsigned int benchmark_repetitions>
void benchmark( char* function_name, auto (*function_to_do)( auto ) ) {
    register unsigned int i=benchmark_repetitions;
    register unsigned long long start=0;
    my_time.reset();
    start=__rdtsc();
    while ( i-- ) {
        auto result = (*function_to_do)( i << 7 );
        #if USE_ASM_TO_PREVENT_ELIMINATION == 1
            asm volatile("" :: "r"(
                // There is no data type in C++ that is smaller than a char, so it will
                //  not throw a segmentation fault error to reinterpret any arbitrary
                //  data type as a char. Although, the compiler might not like it.
                result
            ));
        #endif
    }
    if ( function_name == nullptr ) {
        empty_ticks = (__rdtsc()-start);
        empty_seconds = my_time.elapsed();
        std::cout<< "Empty:\n" << empty_ticks
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << empty_seconds
                << " seconds\n\n";
    } else {
        std::cout<< function_name<<":\n" << (__rdtsc()-start-empty_ticks)
              << " ticks\n" << benchmark_repetitions << " repetitions\n"
               << std::setprecision(15) << (my_time.elapsed()-empty_seconds)
                << " seconds\n\n";
    }
}


int main( void ) {
    void* Cur_Thread=   GetCurrentThread();
    void* Cur_Process=  GetCurrentProcess();
    unsigned long long  Current_Affinity;
    unsigned long long  System_Affinity;
    unsigned long long furthest_affinity;
    unsigned long long nearest_affinity;

    if( ! SetThreadPriority(Cur_Thread,THREAD_PRIORITY_TIME_CRITICAL) ) {
        SetThreadPriority( Cur_Thread, THREAD_PRIORITY_HIGHEST );
    }
    if( ! SetPriorityClass(Cur_Process,REALTIME_PRIORITY_CLASS) ) {
        SetPriorityClass( Cur_Process, HIGH_PRIORITY_CLASS );
    }
    GetProcessAffinityMask( Cur_Process, &Current_Affinity, &System_Affinity );
    furthest_affinity = 0x8000000000000000ULL>>__builtin_clzll(Current_Affinity);
    nearest_affinity  = 0x0000000000000001ULL<<__builtin_ctzll(Current_Affinity);
    SetProcessAffinityMask( Cur_Process, furthest_affinity );
    SetThreadAffinityMask( Cur_Thread, furthest_affinity );

    const int repetitions=524288;

    benchmark<repetitions>( nullptr, empty_function );
    benchmark<repetitions>( "Standard Square Root", standard_sqrt );
    benchmark<repetitions>( "Original Guess Square Root", original_guess_sqrt32 );
    benchmark<repetitions>( "New Guess Square Root", new_guess_sqrt32 );


    SetThreadPriority( Cur_Thread, THREAD_PRIORITY_IDLE );
    SetPriorityClass( Cur_Process, IDLE_PRIORITY_CLASS );
    SetProcessAffinityMask( Cur_Process, nearest_affinity );
    SetThreadAffinityMask( Cur_Thread, nearest_affinity );
    for (;;) { getchar(); }

    return 0;
}

এছাড়াও, মাইক জার্ভিসকে তার টাইমারটির জন্য কৃতিত্ব।

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


2
অপ্টিমাইজেশন অক্ষম করা বাদে ভাল উত্তর। বেঞ্চমার্কিং -O0কোড সময়ের অপচয় একটি কারণ -O0 সাধারণের পরিবর্তে ওভারহেড কোড -O2বা কাজের চাপের উপর নির্ভর করে বন্যভাবে-O3 -march=native পরিবর্তিত হয় । যেমন অতিরিক্ত নামের টিএমপি ওয়ার্সে সময় ব্যয় হয় । জিনিসগুলি অপ্টিমাইজ করা এড়ানোর অন্যান্য উপায় রয়েছে যেমন অপ্টিমাইজার থেকে জিনিসগুলি গোপন করা , নন-ইনলাইন ফাংশনগুলি, বা খালি ইনলাইন asm বিবৃতি। এমনকি ব্যবহারের ঘনিষ্ঠও নয় কারণ কোডের বিভিন্ন বাধা রয়েছে , একই নয় তবে আরও খারাপ। -O0volatile-O0-O0
পিটার

1
উঘ, -Ogকোডের উপর নির্ভর করে এখনও খুব বাস্তববাদী নয়। অন্ততপক্ষে -O2, -O3আরও বেশি বাস্তববাদী। asm volatile("" ::: "+r"(var))সংকলক একটি রেজিস্টারে একটি মানকে রূপায়িত করতে ব্যবহার করুন বা কিছু করুন এবং এর মাধ্যমে ধ্রুবক প্রচারকে পরাজিত করুন।
পিটার কর্ডেস

@ পিটারকার্ডস আপনার অন্তর্দৃষ্টি জন্য আবার ধন্যবাদ। আমি এর সাথে সামগ্রী -O3এবং কোড স্নিপেট আপডেট করেছি asm volatile("" ::: "+r"(var))
জ্যাক গিফিন

1
asm volatile("" ::: "+r"( i ));অপ্রয়োজনীয় মনে হচ্ছে অপ্টিমাইজড কোডে, কম্পাইলারকে লুপের iপাশাপাশি বাস্তবায়িত করতে বাধ্য করার কোনও কারণ নেই i<<7। আপনি tmp -= 128প্রতিবার স্থানান্তরিত করার পরিবর্তে এটি অনুকূলিতকরণ থেকে থামিয়ে দিচ্ছেন । ভাল, যদিও, একটি ফাংশন কল ফল ব্যবহার করা হয় যদি এটা অ- এর void। ভালো লেগেছে int result = (*function_to_do)( i << 7 );। আপনি asmযে ফলাফল উপর একটি বিবৃতি ব্যবহার করতে পারেন ।
পিটার কর্ডেস

@ পিটারকর্ডস আপনাকে আবার অনেক ধন্যবাদ বা আপনার অন্তর্দৃষ্টিগুলি। আমার পোস্টে এখন থেকে রিটার্ন মানটির সংশোধন রয়েছে function_to_doযাতে এটি সরিয়ে function_to_doনা দিয়ে ইনলাইন করা যায়। আপনার আরও কোনও পরামর্শ থাকলে দয়া করে আমাকে জানান।
জ্যাক গিফিন

1

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

#ifdef _WIN32
#include <Windows.h>
#else
#include <sys/time.h>
#endif

/*
 *  A simple timer class to see how long a piece of code takes. 
 *  Usage:
 *
 *  {
 *      static Timer timer("name");
 *
 *      ...
 *
 *      timer.start()
 *      [ The code you want timed ]
 *      timer.stop()
 *
 *      ...
 *  }
 *
 *  At the end of execution, you will get output:
 *
 *  Time for name: XXX seconds
 */
class Timer
{
public:
    Timer(std::string name, bool start_running=false) : 
        _name(name), _accum(0), _running(false)
    {
        if (start_running) start();
    }

    ~Timer() { stop(); report(); }

    void start() {
        if (!_running) {
            _start_time = GetTimeMicroseconds();
            _running = true;
        }
    }
    void stop() {
        if (_running) {
            unsigned long long stop_time = GetTimeMicroseconds();
            _accum += stop_time - _start_time;
            _running = false;
        }
    }
    void report() { 
        std::cout<<"Time for "<<_name<<": " << _accum / 1.e6 << " seconds\n"; 
    }
private:
    // cf. http://stackoverflow.com/questions/1861294/how-to-calculate-execution-time-of-a-code-snippet-in-c
    unsigned long long GetTimeMicroseconds()
    {
#ifdef _WIN32
        /* Windows */
        FILETIME ft;
        LARGE_INTEGER li;

        /* Get the amount of 100 nano seconds intervals elapsed since January 1, 1601 (UTC) and copy it
         *   * to a LARGE_INTEGER structure. */
        GetSystemTimeAsFileTime(&ft);
        li.LowPart = ft.dwLowDateTime;
        li.HighPart = ft.dwHighDateTime;

        unsigned long long ret = li.QuadPart;
        ret -= 116444736000000000LL; /* Convert from file time to UNIX epoch time. */
        ret /= 10; /* From 100 nano seconds (10^-7) to 1 microsecond (10^-6) intervals */
#else
        /* Linux */
        struct timeval tv;

        gettimeofday(&tv, NULL);

        unsigned long long ret = tv.tv_usec;
        /* Adds the seconds (10^0) after converting them to microseconds (10^-6) */
        ret += (tv.tv_sec * 1000000);
#endif
        return ret;
    }
    std::string _name;
    long long _accum;
    unsigned long long _start_time;
    bool _running;
};

1

কেবলমাত্র একটি সাধারণ শ্রেণি যা কোডব্লকটিকে বেঞ্চমার্ক করে:

using namespace std::chrono;

class benchmark {
  public:
  time_point<high_resolution_clock>  t0, t1;
  unsigned int *d;
  benchmark(unsigned int *res) : d(res) { 
                 t0 = high_resolution_clock::now();
  }
  ~benchmark() { t1 = high_resolution_clock::now();
                  milliseconds dur = duration_cast<milliseconds>(t1 - t0);
                  *d = dur.count();
  }
};
// simple usage 
// unsigned int t;
// { // put the code in a block
//  benchmark bench(&t);
//  // ...
//  // code to benchmark
// }
// HERE the t contains time in milliseconds

// one way to use it can be :
#define BENCH(TITLE,CODEBLOCK) \
  unsigned int __time__##__LINE__ = 0;  \
  { benchmark bench(&__time__##__LINE__); \
      CODEBLOCK \
  } \
  printf("%s took %d ms\n",(TITLE),__time__##__LINE__);


int main(void) {
  BENCH("TITLE",{
    for(int n = 0; n < testcount; n++ )
      int a = n % 3;
  });
  return 0;
}

0

বুস্ট :: টাইমার সম্ভবত আপনার প্রয়োজন হিসাবে যথাযথতা দেবে এটি কতটা সময় a = a+1;নেবে তা আপনাকে বলার মতো পর্যাপ্ত কোথাও কোথাও নেই , তবে আমি কী কারণে আপনাকে এমন কোনও কিছু সময় লাগবে যাতে কয়েকটা ন্যানোসেকেন্ড লাগে?


এটি clock()সি ++ স্ট্যান্ডার্ড শিরোনাম থেকে ফাংশন উপর নির্ভর করে ।
পিটার

0

আমি একটি ল্যাম্বডা তৈরি করেছি যা আপনাকে কলটি এন বার বলে কল করে এবং আপনাকে গড় ফিরিয়ে দেয়।

double c = BENCHMARK_CNT(25, fillVectorDeque(variable));

আপনি এখানে সি ++ 11 শিরোনাম খুঁজে পেতে পারেন ।


0

ক্রোনো লাইব্রেরির হাই_রেসোলিউশন_ক্লোর ব্যবহার করে কোডের ব্লকগুলির পারফরম্যান্স পরিমাপের জন্য আমি একটি সহজ ইউটিলিটি তৈরি করেছি: https://github.com/nfergu/codetimer

সময়গুলি বিভিন্ন কীগুলির সাথে রেকর্ড করা যায় এবং প্রতিটি কীগুলির জন্য সময়গুলির একত্রিত ভিউ প্রদর্শিত হতে পারে।

ব্যবহার নিম্নরূপ:

#include <chrono>
#include <iostream>
#include "codetimer.h"

int main () {
    auto start = std::chrono::high_resolution_clock::now();
    // some code here
    CodeTimer::record("mykey", start);
    CodeTimer::printStats();
    return 0;
}

0

আপনি [cxx-rtimers][1]গিটহাবের দিকেও নজর রাখতে পারেন যা কোনও কোড-ব্লকের রান-টাইমের পরিসংখ্যান সংগ্রহের জন্য কয়েকটি শিরোনাম-কেবল রুটিন সরবরাহ করে যেখানে আপনি স্থানীয় পরিবর্তনশীল তৈরি করতে পারেন। এই টাইমারগুলির এমন সংস্করণ রয়েছে যা সি ++ 11-এ স্ট্যান্ড :: ক্রোনো ব্যবহার করে বা বুস্ট লাইব্রেরি থেকে টাইমার বা স্ট্যান্ডার্ড পসিক্স টাইমার ফাংশন ব্যবহার করে। এই টাইমারগুলি কোনও ফাংশনের মধ্যে ব্যয় করা গড়, সর্বোচ্চ এবং সর্বনিম্ন সময়কাল এবং সেই সাথে যতবার ডাকা হবে তার সংখ্যা জানাবে। সেগুলি নীচের হিসাবে সহজভাবে ব্যবহার করা যেতে পারে:

#include <rtimers/cxx11.hpp>

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensive");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

0

আমি কীভাবে এটি করি তা বোঝা যায় না, খুব বেশি কোড নয়, বোঝা সহজ my

void bench(std::function<void()> fnBench, std::string name, size_t iterations)
{
    if (iterations == 0)
        return;
    if (fnBench == nullptr)
        return;
    std::chrono::high_resolution_clock::time_point start, end;
    if (iterations == 1)
    {
        start = std::chrono::high_resolution_clock::now();
        fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    else
    {
        start = std::chrono::high_resolution_clock::now();
        for (size_t i = 0; i < iterations; ++i)
            fnBench();
        end = std::chrono::high_resolution_clock::now();
    }
    printf
    (
        "bench(*, \"%s\", %u) = %4.6lfs\r\n",
        name.c_str(),
        iterations,
        std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()
    );
}

ব্যবহার:

bench
(
    []() -> void // function
    {
        // Put your code here
    },
    "the name of this", // name
    1000000 // iterations
);

0
#include <omp.h>

double start = omp_get_wtime();

// code 

double finish = omp_get_wtime();

double total_time = finish - start;

2
এই কোডটি কীভাবে এবং কেন এই সমস্যার সমাধান করে তার ব্যাখ্যা সহ প্রশ্নটি সমাধান করতে পারে যদিও আপনার পোস্টের গুণমান উন্নত করতে সত্যই সহায়তা করবে এবং সম্ভবত আরও বেশি ভোটের ফলাফল হবে। মনে রাখবেন যে আপনি ভবিষ্যতে পাঠকদের জন্য প্রশ্নের উত্তর দিচ্ছেন, কেবল এখনই জিজ্ঞাসা করা ব্যক্তি নয়। দয়া করে সম্পাদনা ব্যাখ্যা যোগ করতে পারেন এবং সীমাবদ্ধতা এবং অনুমানের কি প্রয়োগ একটি ইঙ্গিত দিতে আপনার উত্তর।
ধর্ম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.