一个非常有趣的会议是关于D-Specific设计模式的,在D社区中,有些人认为它可能是一本关于有效编码技术的书的起点.其他人认为现在为时尚早,因为没有多少人有很多经验,这样一本书的作者会对有效性的概念有一些偏见/个人欣赏.SO是一种更具互动性的媒体(有其局限性).因此,等待'Effective D'出来,如果我们可以分享一些(查杀)建议/技术/模式以使D代码看起来更好,那将是很好的.我认为如果答案会更清楚:
我想为我和我的朋友写一个真正(非常)快速的Sobel算子用于射线追踪器(可以在这里找到源码).以下是我到目前为止所得到的......
首先,假设图像是8位无符号整数数组中逐行的灰度图像存储.
要编写真正的Sobel滤波器,我需要为每个像素计算Gx和Gy.由于原点旁边有6个像素,因此计算出这些数字中的每一个.但SIMD指令允许我处理16或甚至32(AVX)像素.希望运算符的内核具有一些不错的属性,因此我可以通过以下方式计算Gy:
我会做同样的(但转置)计算Gx然后添加两张图片.
一些说明:
(uint8_t >> 2 - uint8_t >> 2) = int7_t //really store as int8_t
int7_t + uint8_t << 1 >> 2 + int7_t = uint8_t
//some precision is lost but I don't care我面临的真正问题是从行到列.因为我无法将图片加载到SIMD寄存器中.我必须三次翻转图像至少不是吗?
一旦原始图片.然后我可以计算Gx和Gy的第一步,然后翻转结果图片以计算第二步.
所以,这是我的问题:
我需要使用SSE2编写一个点积(没有_mm_dp_ps也没有_mm_hadd_ps):
#include <xmmintrin.h>
inline __m128 sse_dot4(__m128 a, __m128 b)
{
const __m128 mult = _mm_mul_ps(a, b);
const __m128 shuf1 = _mm_shuffle_ps(mult, mult, _MM_SHUFFLE(0, 3, 2, 1));
const __m128 shuf2 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(1, 0, 3, 2));
const __m128 shuf3 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(2, 1, 0, 3));
return _mm_add_ss(_mm_add_ss(_mm_add_ss(mult, shuf1), shuf2), shuf3);
}
Run Code Online (Sandbox Code Playgroud)
但我看了生成的汇编程序与gcc 4.9(实验)-O3,我得到:
mulps %xmm1, %xmm0
movaps %xmm0, %xmm3 //These lines
movaps %xmm0, %xmm2 //have no use
movaps %xmm0, %xmm1 //isn't it ?
shufps $57, %xmm0, %xmm3
shufps $78, %xmm0, %xmm2 …Run Code Online (Sandbox Code Playgroud) 我知道为什么我不能使用float作为模板参数以及如何通过分子/分母对设置模板类的静态const float成员.但是我正在尝试基于reinterpret_cast的另一个"hack"到来自IEEE754十六进制写入的"emule"浮点模板参数.
这是一小段代码:
#include <iostream>
#include <cstdint>
template <uint32_t T>
struct MyStruct
{
static const float value;
};
template <uint32_t T>
const float MyStruct<T>::value = *reinterpret_cast<float*>(T);
int main()
{
typedef MyStruct<0x40490fdb> Test;
std::cout << Test::value << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我编译它...
g++ -Wall -pedantic main.cpp -std=c++0x -g
Run Code Online (Sandbox Code Playgroud)
没有任何警告.
并且它分裂......
brugelca@artemis:~/workspace/draft$ ./a.out
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)
这是valgrind输出:
brugelca@artemis:~/workspace/draft$ valgrind ./a.out
==10871== Memcheck, a memory error detector
==10871== Copyright (C) 2002-2012, and GNU GPL'd, by Julian …Run Code Online (Sandbox Code Playgroud) 刚刚测试了两个小程序,
#include <thread>
int main()
{
for (int i = 0; i < 10000000; i++)
{
std::this_thread::yield();
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
和:
#include <thread>
#include <chrono>
int main()
{
using namespace std::literals;
for (int i = 0; i < 10000000; i++)
{
std::this_thread::sleep_for(0s);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在我的系统上得到了各自的计时(Ubuntu 22.04 LTS,内核版本 5.19.0-43-generic),
./a.out 0,33s user 1,36s system 99% cpu 1,687 total
Run Code Online (Sandbox Code Playgroud)
和:
./a.out 0,14s user 0,00s system 99% cpu 0,148 total
Run Code Online (Sandbox Code Playgroud)
为什么std::this_thread::yield()比 慢 10 倍std::this_thread::sleep_for(0s)?
注意 g++ …
让我们看一个std::unordered_set的std::unique_ptr<T>作为一个例子.我可以在其他位置移动该组的元素吗?
#include <unordered_set>
#include <iostream>
#include <memory>
#include <vector>
int main()
{
std::unordered_set<std::unique_ptr<int>> mySet;
mySet.insert(std::make_unique<int>(1));
mySet.insert(std::make_unique<int>(2));
mySet.insert(std::make_unique<int>(3));
std::vector<std::unique_ptr<int>> myVector;
for (auto&& element : mySet)
{
std::cout << *element << std::endl;
//myVector.push_back(element); won't compile as you can only get a const ref to the key
}
}
Run Code Online (Sandbox Code Playgroud)
我有一个非常实用的代码示例,我想这样做,但我减少使用a std::shared_ptr.你知道另一个(更好吗?)的选择吗?
尝试使用不同的文件名创建一些gzip存档我写下以下代码片段.
#include <iostream>
#include <utility>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/gzip.hpp>
boost::iostreams::filtering_ostream&& makeGZipStream(const std::string& archiveName,
const std::string& fileName)
{
boost::iostreams::filtering_ostream theGzipStream;
boost::iostreams::gzip_params theGzipParams;
theGzipParams.file_name = fileName;
theGzipStream.push(boost::iostreams::gzip_compressor{theGzipParams});
theGzipStream.push(boost::iostreams::file_sink{archiveName});
return std::move(theGzipStream);
}
int main()
{
boost::iostreams::filtering_ostream&& theGzipStream = makeGZipStream("archive.gz", "file");
theGzipStream << "This is a test..." << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这(我们可以预期)会产生核心转储,因为makeGZipStream我们尝试通过(rvalue-)引用返回本地堆栈分配的变量.但在这种情况下,副本不是一个选项,因为它boost::iostreams::filtering_ostream是不可复制的.
std::unique_ptr"按值"(由于copy-elision,这个移动甚至不应该出现在C++ 17中),为什么在这种情况下不可能呢?unique_ptr(不那么漂亮)使用的编译器很老了g++ (GCC) 4.9.3.
c++ ×4
c++11 ×3
c ×2
sse ×2
assembly ×1
containers ×1
copy-elision ×1
d ×1
linux ×1
memory ×1
move ×1
noncopyable ×1
optimization ×1
phobos ×1
scheduler ×1
simd ×1
templates ×1