如何通过点积获得峰值 CPU 性能?

2024-05-02

Problem

我一直在研究 HPC,特别是使用矩阵乘法作为我的项目(请参阅我的个人资料中的其他帖子)。我在这些方面取得了不错的成绩,但还不够好。我退后一步,看看我在点积计算方面能做得如何。

点积与矩阵乘法

点积更简单,并且允许我测试 HPC 概念,而无需处理打包和其他相关问题。缓存阻塞仍然是一个问题,这构成了我的第二个问题。

算法

n两个对应的元素double arrays A and B并对它们求和。 Adouble装配中的点积只是一系列movapd, mulpd, addpd。以巧妙的方式展开和排列,可以有成组的movapd/mulpd/addpd分别运行在不同的xmm寄存器,因此是独立的,优化了流水线。当然,事实证明这并不重要,因为我的 CPU 执行乱序。另请注意,重新排列需要剥离最后一次迭代。

其他假设

我不是在编写一般点积的代码。该代码适用于特定尺寸,我不处理边缘情况。这只是为了测试 HPC 概念并看看我可以达到什么类型的 CPU 使用率。

Results

编译为gcc -std=c99 -O2 -m32 -mincoming-stack-boundary=2 -msse3 -mfpmath=sse,387 -masm=intel。我使用的计算机与平常不同。这台计算机有一个i5 540m从而可以获得2.8 GHz * 4 FLOPS/cycle/core = 11.2 GFLOPS/s per core经过两步英特尔睿频加速(两个核心现在都处于开启状态,因此只能进行 2 步……如果我关闭一个核心,则可以进行 4 步加速)。当设置为使用一个线程运行时,32 位 LINPACK 的速度约为 9.5 GFLOPS/s。

       N   Total Gflops/s         Residual
     256         5.580521    1.421085e-014
     384         5.734344   -2.842171e-014
     512         5.791168    0.000000e+000
     640         5.821629    0.000000e+000
     768         5.814255    2.842171e-014
     896         5.807132    0.000000e+000
    1024         5.817208   -1.421085e-013
    1152         5.805388    0.000000e+000
    1280         5.830746   -5.684342e-014
    1408         5.881937   -5.684342e-014
    1536         5.872159   -1.705303e-013
    1664         5.881536    5.684342e-014
    1792         5.906261   -2.842171e-013
    1920         5.477966    2.273737e-013
    2048         5.620931    0.000000e+000
    2176         3.998713    1.136868e-013
    2304         3.370095   -3.410605e-013
    2432         3.371386   -3.410605e-013

问题1

我怎样才能做得比这更好?我什至还没有接近巅峰表现。我已经将汇编代码优化到了天堂。进一步展开可能会稍微提升一点,但较少展开似乎会降低性能。

问题2

When n > 2048,您可以看到性能下降。这是因为我的L1缓存是32KB,当n = 2048 and A and B are double,它们占用整个缓存。如果更大,它们就会从内存中流式传输。

我尝试了缓存阻塞(源代码中未显示),但也许我做错了。任何人都可以提供一些代码或解释如何阻止缓存的点积吗?

源代码

    #include <stdio.h>
    #include <time.h>
    #include <stdlib.h>
    #include <string.h>
    #include <x86intrin.h>
    #include <math.h>
    #include <omp.h>
    #include <stdint.h>
    #include <windows.h>

    // computes 8 dot products
#define KERNEL(address) \
            "movapd     xmm4, XMMWORD PTR [eax+"#address"]      \n\t" \
            "mulpd      xmm7, XMMWORD PTR [edx+48+"#address"]   \n\t" \
            "addpd      xmm2, xmm6                              \n\t" \
            "movapd     xmm5, XMMWORD PTR [eax+16+"#address"]   \n\t" \
            "mulpd      xmm4, XMMWORD PTR [edx+"#address"]      \n\t" \
            "addpd      xmm3, xmm7                              \n\t" \
            "movapd     xmm6, XMMWORD PTR [eax+96+"#address"]   \n\t" \
            "mulpd      xmm5, XMMWORD PTR [edx+16+"#address"]   \n\t" \
            "addpd      xmm0, xmm4                              \n\t" \
            "movapd     xmm7, XMMWORD PTR [eax+112+"#address"]  \n\t" \
            "mulpd      xmm6, XMMWORD PTR [edx+96+"#address"]   \n\t" \
            "addpd      xmm1, xmm5                              \n\t"

#define PEELED(address) \
            "movapd     xmm4, XMMWORD PTR [eax+"#address"]      \n\t" \
            "mulpd      xmm7, [edx+48+"#address"]               \n\t" \
            "addpd      xmm2, xmm6                  \n\t" \
            "movapd     xmm5, XMMWORD PTR [eax+16+"#address"]   \n\t" \
            "mulpd      xmm4, XMMWORD PTR [edx+"#address"]      \n\t" \
            "addpd      xmm3, xmm7                  \n\t" \
            "mulpd      xmm5, XMMWORD PTR [edx+16+"#address"]   \n\t" \
            "addpd      xmm0, xmm4                  \n\t" \
            "addpd      xmm1, xmm5                  \n\t"

inline double 
__attribute__ ((gnu_inline))        
__attribute__ ((aligned(64))) ddot_ref(
    int n,
    const double* restrict A,
    const double* restrict B)
{
    double sum0 = 0.0;
    double sum1 = 0.0;
    double sum2 = 0.0;
    double sum3 = 0.0;
    double sum;
    for(int i = 0; i < n; i+=4) {
        sum0 += *(A + i  ) * *(B + i  );
        sum1 += *(A + i+1) * *(B + i+1);
        sum2 += *(A + i+2) * *(B + i+2);
        sum3 += *(A + i+3) * *(B + i+3);
    }
    sum = sum0+sum1+sum2+sum3;
    return(sum);
}

inline double 
__attribute__ ((gnu_inline))        
__attribute__ ((aligned(64))) ddot_asm
(   int n,
    const double* restrict A,
    const double* restrict B)
{

        double sum;

            __asm__ __volatile__
        (
            "mov        eax, %[A]                   \n\t"
            "mov        edx, %[B]                   \n\t"
            "mov        ecx, %[n]                   \n\t"
            "pxor       xmm0, xmm0                  \n\t"
            "pxor       xmm1, xmm1                  \n\t"
            "pxor       xmm2, xmm2                  \n\t"
            "pxor       xmm3, xmm3                  \n\t"
            "movapd     xmm6, XMMWORD PTR [eax+32]  \n\t"
            "movapd     xmm7, XMMWORD PTR [eax+48]  \n\t"
            "mulpd      xmm6, XMMWORD PTR [edx+32]  \n\t"
            "sar        ecx, 7                      \n\t"
            "sub        ecx, 1                      \n\t" // peel
            "L%=:                                   \n\t"
            KERNEL(64   *   0)
            KERNEL(64   *   1)
            KERNEL(64   *   2)
            KERNEL(64   *   3)
            KERNEL(64   *   4)
            KERNEL(64   *   5)
            KERNEL(64   *   6)
            KERNEL(64   *   7)
            KERNEL(64   *   8)
            KERNEL(64   *   9)
            KERNEL(64   *   10)
            KERNEL(64   *   11)
            KERNEL(64   *   12)
            KERNEL(64   *   13)
            KERNEL(64   *   14)
            KERNEL(64   *   15)
            "lea        eax, [eax+1024]             \n\t"
            "lea        edx, [edx+1024]             \n\t"
            "                                       \n\t"
            "dec        ecx                         \n\t"
            "jnz        L%=                         \n\t" // end loop
            "                                       \n\t"
            KERNEL(64   *   0)
            KERNEL(64   *   1)
            KERNEL(64   *   2)
            KERNEL(64   *   3)
            KERNEL(64   *   4)
            KERNEL(64   *   5)
            KERNEL(64   *   6)
            KERNEL(64   *   7)
            KERNEL(64   *   8)
            KERNEL(64   *   9)
            KERNEL(64   *   10)
            KERNEL(64   *   11)
            KERNEL(64   *   12)
            KERNEL(64   *   13)
            KERNEL(64   *   14)
            PEELED(64   *   15)
            "                                       \n\t"
            "addpd      xmm0, xmm1                  \n\t" // summing result
            "addpd      xmm2, xmm3                  \n\t"
            "addpd      xmm0, xmm2                  \n\t" // cascading add
            "movapd     xmm1, xmm0                  \n\t" // copy xmm0
            "shufpd     xmm1, xmm0, 0x03            \n\t" // shuffle
            "addsd      xmm0, xmm1                  \n\t" // add low qword
            "movsd      %[sum], xmm0                \n\t" // mov low qw to sum
            : // outputs
            [sum]   "=m"    (sum)
            : // inputs
            [A] "m" (A),
            [B] "m" (B), 
            [n] "m" (n)
            : //register clobber
            "memory",
            "eax","ecx","edx","edi",
            "xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7"
            );
        return(sum);
}

int main()
{
    // timers
    LARGE_INTEGER frequency, time1, time2;
    double time3;
    QueryPerformanceFrequency(&frequency);
    // clock_t time1, time2;
    double gflops;

    int nmax = 4096;
    int trials = 1e7;
    double sum, residual;
    FILE *f = fopen("soddot.txt","w+");

    printf("%16s %16s %16s\n","N","Total Gflops/s","Residual");
    fprintf(f,"%16s %16s %16s\n","N","Total Gflops/s","Residual");

    for(int n = 256; n <= nmax; n += 128 ) {
        double* A = NULL;
        double* B = NULL;
        A = _mm_malloc(n*sizeof(*A), 64); if (!A) {printf("A failed\n"); return(1);}
        B = _mm_malloc(n*sizeof(*B), 64); if (!B) {printf("B failed\n"); return(1);}

        srand(time(NULL));

        // create arrays
        for(int i = 0; i < n; ++i) {
            *(A + i) = (double) rand()/RAND_MAX;
            *(B + i) = (double) rand()/RAND_MAX;
        }

        // warmup
        sum = ddot_asm(n,A,B);

        QueryPerformanceCounter(&time1);
        // time1 = clock();
        for (int count = 0; count < trials; count++){
            // sum = ddot_ref(n,A,B);
            sum = ddot_asm(n,A,B);
        }
        QueryPerformanceCounter(&time2);
        time3 = (double)(time2.QuadPart - time1.QuadPart) / frequency.QuadPart;
        // time3 = (double) (clock() - time1)/CLOCKS_PER_SEC;
        gflops = (double) (2.0*n*trials)/time3/1.0e9;
        residual = ddot_ref(n,A,B) - sum;
        printf("%16d %16f %16e\n",n,gflops,residual);
        fprintf(f,"%16d %16f %16e\n",n,gflops,residual);

        _mm_free(A);
        _mm_free(B);
    }
    fclose(f);
    return(0); // successful completion
}

编辑:装配说明

点积只是两个数字的乘积的重复和:sum += a[i]*b[i]. sum必须初始化为0在第一次迭代之前。矢量化后,您可以一次进行 2 次求和,并且必须在最后求和:[sum0 sum1] = [a[i] a[i+1]]*[b[i] b[i+1]], sum = sum0 + sum1。在(Intel)汇编中,这是 3 个步骤(初始化之后):

pxor   xmm0, xmm0              // accumulator [sum0 sum1] = [0 0]
movapd xmm1, XMMWORD PTR [eax] // load [a[i] a[i+1]] into xmm1
mulpd  xmm1, XMMWORD PTR [edx] // xmm1 = xmm1 * [b[i] b[i+1]]
addpd  xmm0, xmm1              // xmm0 = xmm0 + xmm1

此时你没有什么特别的,编译器可以想出这个。通过将代码展开足够多次以使用所有内容,通常可以获得更好的性能xmm可供您使用的寄存器(32 位模式下有 8 个寄存器)。因此,如果您将其展开 4 次,就可以使用所有 8 个寄存器xmm0通过xmm7。您将有 4 个累加器和 4 个寄存器来存储结果movapd and addpd。同样,编译器可以提出这个。真正的思考部分是试图想出一种流水线代码的方法,即让 MOV/MUL/ADD 组中的每条指令在不同的寄存器上操作,以便所有 3 条指令同时执行(通常是这种情况)大多数CPU)。这就是你击败编译器的方法。因此,您必须对 4x 展开的代码进行模式化才能做到这一点,这可能需要提前加载向量并剥离第一次或最后一次迭代。这是什么KERNEL(address)是。为了方便起见,我制作了 4x 展开的流水线代码的宏。这样我只需更改即可轻松将其展开为 4 的倍数address. Each KERNEL计算 8 点积。


要回答您的总体问题,您无法使用点积实现峰值性能。

问题是您的 CPU 每个时钟周期可以执行一次 128 位负载,而要执行点积,您需要每个时钟周期执行两个 128 位负载。

但它比大 n 更糟糕。第二个问题的答案是,点积受内存限制,而不是计算限制,因此它无法对具有快速核心的大 n 进行并行化。这在这里有更好的解释为什么向量化循环没有提高性能 https://stackoverflow.com/questions/18159455/why-vectorizing-the-loop-does-not-have-performance-improvement/18159503#18159503。这是快速内核并行化的一个大问题。我花了一段时间才弄清楚这一点,但学习这一点非常重要。

实际上,很少有基本算法可以充分受益于快速内核上的并行化。就 BLAS 算法而言,只有 3 级算法 (O(n^3))(例如矩阵乘法)真正受益于并行化。在慢速核心上情况会更好,例如使用 GPU 和 Xeon Phi,因为内存速度和核心速度之间的差异要小得多。

如果您想找到一种可以在小 n 情况下接近峰值触发器的算法,请尝试例如标量 * 向量或标量 * 向量之和。第一种情况应在每个时钟周期进行一次加载、一次乘法和一次存储,而第二种情况应在每个时钟周期进行一次乘法、一次加法和一次加载。

我在 Core 2 Duo 上测试了以下代码[电子邮件受保护] /cdn-cgi/l/email-protection在 Knoppix 7.3 32 位中。我得到了大约 75% 的标量积峰值和 75% 的标量积之和峰值。标量积的触发器/周期为 2,标量积的总和为 4。

编译为g++ -msse2 -O3 -fopenmp foo.cpp -ffast-math

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
#include <x86intrin.h>

void scalar_product(double * __restrict a, int n) {
    a = (double*)__builtin_assume_aligned (a, 64);
    double k = 3.14159;
    for(int i=0; i<n; i++) {
        a[i] = k*a[i]; 
    }
}

void scalar_product_SSE(double * __restrict a, int n) {
    a = (double*)__builtin_assume_aligned (a, 64);
    __m128d k = _mm_set1_pd(3.14159);    
    for(int i=0; i<n; i+=8) {
        __m128d t1 = _mm_load_pd(&a[i+0]);
        _mm_store_pd(&a[i],_mm_mul_pd(k,t1));
        __m128d t2 = _mm_load_pd(&a[i+2]);
        _mm_store_pd(&a[i+2],_mm_mul_pd(k,t2));
        __m128d t3 = _mm_load_pd(&a[i+4]);
        _mm_store_pd(&a[i+4],_mm_mul_pd(k,t3));
        __m128d t4 = _mm_load_pd(&a[i+6]);
        _mm_store_pd(&a[i+6],_mm_mul_pd(k,t4));
    }
}

double scalar_sum(double * __restrict a, int n) {
    a = (double*)__builtin_assume_aligned (a, 64);
    double sum = 0.0;    
    double k = 3.14159;
    for(int i=0; i<n; i++) {
        sum += k*a[i]; 
    }
    return sum;
}

double scalar_sum_SSE(double * __restrict a, int n) {
    a = (double*)__builtin_assume_aligned (a, 64);
    __m128d sum1 = _mm_setzero_pd();
    __m128d sum2 = _mm_setzero_pd();
    __m128d sum3 = _mm_setzero_pd();
    __m128d sum4 = _mm_setzero_pd();
    __m128d k = _mm_set1_pd(3.14159);   
    for(int i=0; i<n; i+=8) {
        __m128d t1 = _mm_load_pd(&a[i+0]);
        sum1 = _mm_add_pd(_mm_mul_pd(k,t1),sum1);
        __m128d t2 = _mm_load_pd(&a[i+2]);
        sum2 = _mm_add_pd(_mm_mul_pd(k,t2),sum2);
        __m128d t3 = _mm_load_pd(&a[i+4]);
        sum3 = _mm_add_pd(_mm_mul_pd(k,t3),sum3);
        __m128d t4 = _mm_load_pd(&a[i+6]);
        sum4 = _mm_add_pd(_mm_mul_pd(k,t4),sum4);      
    }
    double tmp[8];
    _mm_storeu_pd(&tmp[0],sum1);
    _mm_storeu_pd(&tmp[2],sum2);
    _mm_storeu_pd(&tmp[4],sum3);
    _mm_storeu_pd(&tmp[6],sum4);
    double sum = 0;
    for(int i=0; i<8; i++) sum+=tmp[i];
    return sum;
}

int main() {
    //_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
    //_mm_setcsr(_mm_getcsr() | 0x8040);
    double dtime, peak, flops, sum;
    int repeat = 1<<18;
    const int n = 2048;
    double *a = (double*)_mm_malloc(sizeof(double)*n,64);
    double *b = (double*)_mm_malloc(sizeof(double)*n,64);
    for(int i=0; i<n; i++) a[i] = 1.0*rand()/RAND_MAX;

    dtime = omp_get_wtime();
    for(int r=0; r<repeat; r++) {
        scalar_product_SSE(a,n);
    }
    dtime = omp_get_wtime() - dtime;
    peak = 2*2.67;
    flops = 1.0*n/dtime*1E-9*repeat;
    printf("time %f, %f, %f\n", dtime,flops, flops/peak);

    //for(int i=0; i<n; i++) a[i] = 1.0*rand()/RAND_MAX;
    //sum = 0.0;    
    dtime = omp_get_wtime();
    for(int r=0; r<repeat; r++) {
        scalar_sum_SSE(a,n);
    }
    dtime = omp_get_wtime() - dtime;
    peak = 2*2*2.67;
    flops = 2.0*n/dtime*1E-9*repeat;
    printf("time %f, %f, %f\n", dtime,flops, flops/peak);
    //printf("sum %f\n", sum);

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何通过点积获得峰值 CPU 性能? 的相关文章

  • 如何在C++中实现模板类协变?

    是否可以以这样一种方式实现类模板 如果模板参数相关 一个对象可以转换为另一个对象 这是一个展示这个想法的例子 当然它不会编译 struct Base struct Derived Base template
  • 使用 Microsoft Graph API 订阅 Outlook 推送通知时出现 400 错误请求错误

    我正在尝试使用 Microsoft Graph API 创建订阅以通过推送通知获取 Outlook 电子邮件 mentions 我在用本文档 https learn microsoft com en us graph api subscri
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 为什么 Firefox 会忽略缓存标头并在刷新时重新验证?

    我有一些不可变的图像资源 可以永久缓存 Chrome 似乎尊重我的响应标头 并且不会重新验证资源 以下是 Chrome 中其中一项资源的示例 正如你所看到的 我包括cache control public max age expires e
  • 写入和读取文本文件 - C# Windows 通用平台应用程序 Windows 10

    有用 但在显示任何内容之前 您必须在文本框中输入内容 我想那是因为我使用了 TextChanged 事件处理程序 如果我希望它在没有用户交互的情况下显示文本文件的内容 我应该使用哪个事件处理程序 因此 我想在按下按钮时将一些数据写入 C W
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 在 ASP.Net Core 2.0 中导出到 Excel

    我曾经使用下面的代码在 ASP NET MVC 中将数据导出到 Excel Response AppendHeader content disposition attachment filename ExportedHtml xls Res
  • 使用安全函数在 C 中将字符串添加到字符串

    我想将文件名复制到字符串并附加 cpt 但我无法使用安全函数 strcat s 来做到这一点 错误 字符串不是空终止的 我确实设置了 0 如何使用安全函数修复此问题 size strlen locatie size nieuw char m
  • 是否有比 lex/flex 更好(更现代)的工具来生成 C++ 分词器?

    我最近将源文件解析添加到现有工具中 该工具从复杂的命令行参数生成输出文件 命令行参数变得如此复杂 以至于我们开始允许它们作为一个文件提供 该文件被解析为一个非常大的命令行 但语法仍然很尴尬 因此我添加了使用更合理的语法解析源文件的功能 我使
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • 更改窗口的内容 (WPF)

    我创建了一个简单的 WPF 应用程序 它有两个 Windows 用户在第一个窗口中填写一些信息 然后单击 确定 这会将他们带到第二个窗口 这工作正常 但我试图将两个窗口合并到一个窗口中 这样只是内容发生了变化 我设法找到了这个更改窗口内容时
  • 检查 url 是否指向文件或页面

    我们需要以下内容 如果文件确实是文件 则从 URL 下载该文件 否则 如果它是一个页面 则什么也不做 举个简单的例子 我有以下命令来下载文件 My Computer Network DownloadFile http www wired c
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • 如何构建印度尼西亚电话号码正则表达式

    这些是一些印度尼西亚的电话号码 08xxxxxxxxx 至少包含 11 个字符长度 08xxxxxxxxxxx 始终以 08 开头 我发现这个很有用 Regex regex new Regex 08 0 9 0 9 0 9 0 9 0 9
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但

随机推荐

  • 将二进制文件转换为图像

    我需要找到一种将二进制文件转换为图像的快速方法 二进制文件由 N 个NN 矩阵 我想将 0 与一种颜色关联 将 1 与另一种颜色关联 我需要对超过 1000 个二进制文件执行此操作 如果可能的话 我想避免使用 MatLab 有没有任何工具
  • UITextView突出显示的文本颜色或类似的选项?

    我有一个习惯UITableViewCell with a UILabel and a UITextView in it 我希望当用户突出显示时 这两个文本都显示为白色UITableViewCell 显然设置起来非常简单highlighted
  • 在 C# 中快速加载/读取 TIFF 文件

    我正在编写一个处理 TIFF 图像的 C 应用程序 主要是显示文件 重新排序页面 删除页面 分割多页图像 将单个图像合并为一个多页图像等 我们处理的大多数图像都较小 无论是文件大小还是页码 但也有一些较大的图像 显示图像时 我们需要将多页
  • SSRS 导出到 Excel 创建附加列

    我有一个 SSRS 报告 当我导出到 Excel 时 在 Excel 中查看时会创建不需要的列 确保不创建额外列的最佳方法是什么 我尝试将表行的位置设置为0in 0in但这并没有解决问题 随附的屏幕截图是报告在 Visual Studio
  • 使用 decltype() 声明函数签名

    是否可以声明一个函数bar与函数具有相同的签名foo int foo int a return 0 decltype foo bar return 1 imaginary syntax 我认为这同样适用于 typedef 和别名 您可以使用
  • Oracle SQL:从表中选择数据和分区名称并截断分区

    这是一个由两部分组成的问题 1 是否可以根据数据所在的分区使用 select 语句检索其名称ROWID或者其他一些标识符 eg SELECT DATA ID CATEGORY VALUE PARTITION NAME FROM MYTABL
  • Spring - 捕获bean创建异常

    我想在我的代码中捕获 bean 实例化异常 我有什么选择 一种方法是使用基于 Java 的容器配置 Configuration public class AppConfig Bean public SomeBean someBean try
  • Android 中的 Sqlite 全文搜索对非英语字符的 Unicode 支持

    滚动到末尾以跳过说明 背景 在我的 Android 应用程序中 我想使用非英语 Unicode 文本字符串来搜索存储在 SQLite 数据库中的文本文档 字段中的匹配项 我了解到 所以我认为 我需要做的是实施一个使用 fts3 fts4 进
  • 如何在 R 中手动编写正态分布核的似然值?

    具体来说 如何编码 x 和 mu 之差的乘积 精度矩阵以及 x 和 mu 之差的转置 我下面的代码正确吗 提前致谢 colSums dat mu mat solve sigma colSums dat mu mat 其中 mu mat 是重
  • 从类型“DBNull”到类型“String”的转换无效 vb.net

    使用下面给出的代码时显示一个错误 错误是 Conversion from type DBNull to type String is not valid 帮助我找到合适的解决方案 谢谢 Code cmd2 CommandText SELEC
  • PHP is_file 和服务器根相对路径

    请问如何使用 is file 和 folder file jpg 这样的路径 谢谢你 如果路径以 开头 则表示该路径是绝对路径 当路径是相对路径时 即不以 开头 则采用相对于 php 脚本的路径 如果您希望 folder file jpg
  • 修改文件流

    我现在正在开发一个允许编辑非常大的文本文件 4Gb 的类 嗯 这可能听起来有点愚蠢 但我不明白如何修改流中的文本 这是我的代码 public long Replace String text1 String text2 long repla
  • 在 docker windows 上运行 linux 容器

    我在 Windows 10 机器上安装了 Docker for Windows 它要求我启用 HyperV 功能 一切都安装正确并且运行良好 虽然有一件事让我大吃一惊 我实际上能够在 docker windows 上运行 Linux 容器
  • Python 字符串参数解析

    我正在 python 中使用 cmd 类 它将所有参数作为一个大字符串传递给我 将此 arg 字符串标记为 args 数组的最佳方法是什么 Example args arg arg1 arg2 with quotes arg4 arg5 1
  • 无法绑定多部分标识符

    我在 SO 上看到过类似的错误 但我找不到解决我的问题的方法 我有一个 SQL 查询 例如 SELECT DISTINCT a maxa b mahuyen a tenxa b tenhuyen ISNULL dkcd tong 0 AS
  • 无法将值写入密钥\使用管理员帐户在 Windows 7 计算机中安装 SSMS 显示软件

    我在安装SQL Server 2014时出现以下错误 无法将值写入键 SOFTWARE 验证您是否有足够的权限访问该密钥 或联系您的支持人员 当它尝试安装 SSMS 并且我的计算机正在运行 Windows 7 时 就会发生这种情况 为了使其
  • 强制 Javascript 编码风格的工具[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要自动检查不同人编写的javascript源代码的风格 你知道有什么好的工具可以做到这一点吗 与 emacs 集成将是一个优势 先感谢
  • iPhone 网络应用程序可以获取 GPS 位置吗?

    有没有一种简单的方法来设计一个网站来促进iphone用户提供gps网站坐标 我想知道表单字段是否有命名约定 例如 让用户以自动方式输入 我正在考虑建立一个基于位置的网站 并希望为 iPhone 和其他移动用户 量身定制 我意识到 iPhon
  • Android sqlite插入记录如果不存在

    我想将一个新项目 Cheese 添加到 sqlite 表中 但前提是它不存在 我的表中只有两列 id KEY ROWID PR 和product name KEY NAME PR 我一直在尝试使用这些代码 但它给了我一个错误 public
  • 如何通过点积获得峰值 CPU 性能?

    Problem 我一直在研究 HPC 特别是使用矩阵乘法作为我的项目 请参阅我的个人资料中的其他帖子 我在这些方面取得了不错的成绩 但还不够好 我退后一步 看看我在点积计算方面能做得如何 点积与矩阵乘法 点积更简单 并且允许我测试 HPC