Lăn riêng của bạn rất đơn giản profiler không phải là khó. Chèn vào main():
int main()
{
profileCpuUsage(1); // start timer #1
well_written_function();
profileCpuUsage(2); // stop timer #1, and start timer #2
badly_written_function();
profileCpuUsage(-1); // print stats for timers #1 and #2
return 0;
}
nơi:
#define NUMBER(a) ((int)(sizeof(a)/sizeof(a)[0]))
void profileCpuUsage(int slice)
{
static struct {
int iterations;
double elapsedTime;
} slices[30]; // 0 is a don't care slice
if (slice < 0) { // -1 = print
if (slices[0].iterations)
for (slice = 1; slice < NUMBER(slices); slice++)
printf("Slice %2d Iterations %7d Seconds %7.3f\n", slice,
slices[slice].iterations, slices[slice].elapsedTime);
}
else {
static int i; // = previous slice
static double t; // = previous t1
const double t1 = realElapsedTime(); // see below for definition
assert (slice < NUMBER(slices));
slices[i].iterations += 1;
slices[i].elapsedTime += t1 - t; // i = 0 first time through
i = slice;
t = t1;
}
}
Bây giờ phải thừa nhận là trong ví dụ đơn giản bằng cách sử dụng profileCpuUsage này() không thêm nhiều lợi ích. Và nó có bất lợi khi yêu cầu bạn thủ công cụ mã của bạn bằng cách gọi profileCpuUsage() tại các vị trí thích hợp.
Nhưng ưu điểm bao gồm:
- Bạn có thể thời gian bất kỳ mảnh mã, không chỉ là thủ tục.
- Nhanh chóng thêm và xóa, khi bạn thực hiện tìm kiếm nhị phân để tìm và/hoặc xóa các điểm nóng mã.
- Nó chỉ tập trung vào mã bạn quan tâm.
- Di động!
- KISS
Một khéo léo điều phi di động là xác định các chức năng realElapsedTime() để nó cung cấp đủ chi tiết để có được thời gian hợp lệ. Điều này thường làm việc cho tôi (bằng cách sử dụng API của Windows dưới Cygwin):
#include <windows.h>
double realElapsedTime(void) // <-- granularity about 50 microsec on test machines
{
static LARGE_INTEGER freq, start;
LARGE_INTEGER count;
if (!QueryPerformanceCounter(&count))
assert(0 && "QueryPerformanceCounter");
if (!freq.QuadPart) { // one time initialization
if (!QueryPerformanceFrequency(&freq))
assert(0 && "QueryPerformanceFrequency");
start = count;
}
return (double)(count.QuadPart - start.QuadPart)/freq.QuadPart;
}
Đối với Unix thẳng có những điểm chung:
double realElapsedTime(void) // returns 0 first time called
{
static struct timeval t0;
struct timeval tv;
gettimeofday(&tv, 0);
if (!t0.tv_sec)
t0 = tv;
return tv.tv_sec - t0.tv_sec + (tv.tv_usec - t0.tv_usec)/1000000.;
}
realElapsedTime() tạo ra khoảng thời gian tường đồng hồ, không xử lý thời gian, mà thường là những gì tôi muốn.
Ngoài ra còn có các phương pháp ít di động khác để đạt được độ chi tiết mịn hơn bằng cách sử dụng RDTSC; xem ví dụ: http://en.wikipedia.org/wiki/Time_Stamp_Counter và các liên kết của nó, nhưng tôi chưa thử.
Chỉnh sửa: câu trả lời rất hay của ravenspoint có vẻ không quá khác biệt so với tôi. Và câu trả lời của anh ấy sử dụng các chuỗi mô tả tốt đẹp, chứ không phải chỉ là những con số xấu xí mà tôi thường cảm thấy thất vọng.Nhưng điều này có thể được khắc phục chỉ với khoảng một tá dòng phụ (nhưng điều này gần như tăng gấp đôi số số dòng!).
Lưu ý rằng chúng tôi muốn tránh bất kỳ việc sử dụng malloc() và thậm chí tôi không chắc chắn về strcmp(). Vì vậy, số lượng lát không bao giờ tăng lên. Và các va chạm băm đơn giản là gắn cờ nó thay vì được giải quyết: profiler của con người có thể sửa lỗi này bằng cách chạm thủ công số lượng lát từ 30 hoặc bằng cách thay đổi mô tả. chưa được kiểm tra
static unsigned gethash(const char *str) // "djb2", for example
{
unsigned c, hash = 5381;
while ((c = *str++))
hash = ((hash << 5) + hash) + c; // hash * 33 + c
return hash;
}
void profileCpuUsage(const char *description)
{
static struct {
int iterations;
double elapsedTime;
char description[20]; // added!
} slices[30];
if (!description) {
// print stats, but using description, mostly unchanged...
}
else {
const int slice = gethash(description) % NUMBER(slices);
if (!slices[slice].description[0]) { // if new slice
assert(strlen(description) < sizeof slices[slice].description);
strcpy(slices[slice].description, description);
}
else if (!!strcmp(slices[slice].description, description)) {
strcpy(slices[slice].description, "!!hash conflict!!");
}
// remainder unchanged...
}
}
Và điểm khác là thường bạn sẽ muốn vô hiệu hóa hồ sơ này cho các phiên bản phát hành; điều này cũng áp dụng cho câu trả lời của ravenspoint. Điều này có thể được thực hiện bằng các trick của việc sử dụng một vĩ mô ác để xác định nó đi:
#define profileCpuUsage(foo) // = nothing
Nếu đây được thực hiện, bạn sẽ tất nhiên cần phải thêm dấu ngoặc đơn để định nghĩa để vô hiệu hóa các macro vô hiệu hóa:
void (profileCpuUsage)(const char *description)...
Thường được gọi là "hồ sơ cuộc gọi", và tôi khá chắc Visual Studio sẽ làm điều đó. Mặc dù bộ nhớ của tôi hơi mơ hồ một vài năm kể từ khi tôi thực hiện bất kỳ sự phát triển Windows nào. –
Tôi khá chắc chắn vtune cho phép phân tích nơi bạn có thể xem và sắp xếp theo tổng thời gian tiêu thụ bao gồm các chức năng mà nó gọi. Tuy nhiên, để được sử dụng, bạn cần một intuituion hợp lý của bao nhiêu thời gian nên được chi tiêu trong đó chức năng. – torak
@torak: có thể nhớ tên của đối tượng địa lý không? - Tôi có một nắm bắt thô về các chức năng nhất định nên mất bao lâu vì vậy tôi chắc chắn rằng một sự cố như vậy sẽ rất hữu ích thực sự. – Mick