Hôm nay tôi đọc mã bằng cách sử dụng bảng tra cứu thay vì nếu khác để cắt hai giá trị uint8 tổng hợp. Bản đồ là tôi trong số i={0...255}
và 255 trong số i={256...511}
. Tôi tự hỏi mức độ lớn của lợi ích này có thể là gì và cố gắng tìm ra, sử dụng gprof,Bảng tìm kiếm so với if-else
g++ -std=c++0x -pg perfLookup.cpp -O2 -o perfLookup && ./perfLookup && gprof perfLookup |less
với mã được đính kèm bên dưới. Bây giờ không có cờ gzip -O2 nói rằng tra cứu() mất 45% và ifelse() như 48% thời gian thực hiện. Với -O2 mặc dù nó là 56% cho tra cứu() và 43% cho ifelse(). Nhưng điểm chuẩn này có đúng không? Có lẽ rất nhiều mã được tối ưu hóa đi từ dst là không bao giờ đọc?
#include <iostream>
#include <cstdint>
#include <vector>
void lookup(std::vector<uint8_t> src, int repeat) {
uint8_t lookup[511];
for (int i = 0; i < 256; i++) {
lookup[i] = i;
}
for (int i = 256; i < 512; i++) {
lookup[i] = 255;
}
std::vector<uint8_t> dst(src.size());
for (int i = 0; i < repeat; i++) {
for (int i = 0; i < src.size(); i++) {
dst[i] = lookup[src[i]];
}
}
}
void ifelse(std::vector<uint8_t> src, int repeat) {
std::vector<uint8_t> dst(src.size());
for (int i = 0; i < repeat; i++) {
for (int i = 0; i < src.size(); i++) {
dst[i] = (src[i] > 255) ? 255 : src[i];
}
}
}
int main()
{
int n = 10000;
std::vector<uint8_t> src(n);
for (int i = 0; i < src.size(); i++) {
src[i] = rand() % 510;
}
lookup(src, 10000);
ifelse(src, 10000);
}
đang Cập nhật:
#include <iostream>
#include <cstdint>
#include <cstring>
#include <vector>
#include <algorithm>
// g++ -std=c++0x -pg perfLookup.cpp -O2 -o perfLookup && ./perfLookup && gprof perfLookup |less
std::vector<uint16_t> lookup(std::vector<uint16_t> src, int repeat) {
uint16_t lookup[511];
for (int i = 0; i < 256; i++) {
lookup[i] = i;
}
for (int i = 256; i < 511; i++) {
lookup[i] = 255;
}
std::vector<uint16_t> dst(src.size());
for (int i = 0; i < repeat; i++) {
for (int k = 0; k < src.size(); k++) {
dst[k] = lookup[src[k]];
}
}
return dst;
}
std::vector<uint16_t> ifelse(std::vector<uint16_t> src, int repeat) {
std::vector<uint16_t> dst(src.size());
for (int i = 0; i < repeat; i++) {
for (int k = 0; k < src.size(); k++) {
dst[k] = (src[k] > 255) ? 255 : src[k];
}
}
return dst;
}
std::vector<uint16_t> copyv(std::vector<uint16_t> src, int repeat) {
std::vector<uint16_t> dst(src.size());
for (int i = 0; i < repeat; i++) {
dst = src;
for (int k = 0; k < src.size(); k++) {
if (dst[k] > 255) {
dst[k] = 255;
}
}
}
return dst;
}
std::vector<uint16_t> copyC(std::vector<uint16_t> src, int repeat)
{
uint16_t* dst = (uint16_t *) malloc(sizeof(uint16_t) * src.size()); // Alloc array for dst
for (int i = 0; i < repeat; i++) {
std::memcpy(dst, &src[0], sizeof(uint16_t) * src.size()); // copy src into array
for (int k = 0; k < src.size(); k++) {
if ((dst[k] & 0xFF00) != 0)
dst[k] = 0x00FF;
}
}
free(dst);
return std::vector<uint16_t>();
}
int main()
{
int n = 10000;
std::vector<uint16_t> src(n);
for (int i = 0; i < src.size(); i++) {
src[i] = rand() % 510;
}
std::vector<uint16_t> dst;
dst = lookup(src, 10000);
dst = ifelse(src, 10000);
dst = copyv(src, 10000);
}
Lưu ý rằng bạn đang đo lường việc khởi tạo bảng tra cứu như một phần của điểm chuẩn. Thông thường bạn khởi tạo một bảng tra cứu một cách riêng biệt và không inlcude nó trong điểm chuẩn. –
Tôi sẽ không bao gồm việc khởi tạo bảng tra cứu vào hàm được mô phỏng vì điều này có thể được thực hiện chỉ một lần trong khi thực hiện chương trình. –
Một số thay đổi tôi sẽ thực hiện đối với mã: Sử dụng đối số 'src' và thực hiện việc cắt tại chỗ - lưu ý rằng đây là bản sao, không phải là tham chiếu đến bản gốc. Trả về vectơ đó từ hàm, nếu không thì trình biên dịch cũng có thể loại bỏ tất cả các mã từ các hàm vì biến cục bộ không bao giờ được sử dụng. Tạo và lưu trữ bảng tra cứu bên ngoài mã kiểm tra - không thêm các thao tác sẽ không ảnh hưởng đến kết quả. –