Desoptimização de um programa para o pipeline nas CPUs da família Intel Sandybridge
Estou atormentando meu cérebro há uma semana tentando concluir essa tarefa e espero que alguém aqui possa me levar ao caminho certo. Deixe-me começar com as instruções do instrutor:
Sua tarefa é o oposto de nossa primeira tarefa de laboratório, que era otimizar um programa de números primos. Seu objetivo nesta tarefa é pessimizar o programa, ou seja, torná-lo mais lento. Ambos são programas com uso intenso de CPU. Eles levam alguns segundos para serem executados em nossos computadores de laboratório. Você não pode alterar o algoritmo.
Para desativar o programa, use seu conhecimento de como o pipeline Intel i7 opera. Imagine maneiras de reordenar os caminhos das instruções para introduzir WAR, RAW e outros perigos. Pense em maneiras de minimizar a eficácia do cache. Seja diabolicamente incompetent
A tarefa deu uma escolha de programas da Whetstone ou Monte-Carlo. Os comentários sobre a eficácia do cache são aplicáveis apenas ao Whetstone, mas eu escolhi o programa de simulação de Monte-Carlo:
// Un-modified baseline for pessimization, as given in the assignment
#include <algorithm> // Needed for the "max" function
#include <cmath>
#include <iostream>
// A simple implementation of the Box-Muller algorithm, used to generate
// gaussian random numbers - necessary for the Monte Carlo method below
// Note that C++11 actually provides std::normal_distribution<> in
// the <random> library, which can be used instead of this function
double gaussian_box_muller() {
double x = 0.0;
double y = 0.0;
double euclid_sq = 0.0;
// Continue generating two uniform random variables
// until the square of their "euclidean distance"
// is less than unity
do {
x = 2.0 * rand() / static_cast<double>(RAND_MAX)-1;
y = 2.0 * rand() / static_cast<double>(RAND_MAX)-1;
euclid_sq = x*x + y*y;
} while (euclid_sq >= 1.0);
return x*sqrt(-2*log(euclid_sq)/euclid_sq);
}
// Pricing a European vanilla call option with a Monte Carlo method
double monte_carlo_call_price(const int& num_sims, const double& S, const double& K, const double& r, const double& v, const double& T) {
double S_adjust = S * exp(T*(r-0.5*v*v));
double S_cur = 0.0;
double payoff_sum = 0.0;
for (int i=0; i<num_sims; i++) {
double gauss_bm = gaussian_box_muller();
S_cur = S_adjust * exp(sqrt(v*v*T)*gauss_bm);
payoff_sum += std::max(S_cur - K, 0.0);
}
return (payoff_sum / static_cast<double>(num_sims)) * exp(-r*T);
}
// Pricing a European vanilla put option with a Monte Carlo method
double monte_carlo_put_price(const int& num_sims, const double& S, const double& K, const double& r, const double& v, const double& T) {
double S_adjust = S * exp(T*(r-0.5*v*v));
double S_cur = 0.0;
double payoff_sum = 0.0;
for (int i=0; i<num_sims; i++) {
double gauss_bm = gaussian_box_muller();
S_cur = S_adjust * exp(sqrt(v*v*T)*gauss_bm);
payoff_sum += std::max(K - S_cur, 0.0);
}
return (payoff_sum / static_cast<double>(num_sims)) * exp(-r*T);
}
int main(int argc, char **argv) {
// First we create the parameter list
int num_sims = 10000000; // Number of simulated asset paths
double S = 100.0; // Option price
double K = 100.0; // Strike price
double r = 0.05; // Risk-free rate (5%)
double v = 0.2; // Volatility of the underlying (20%)
double T = 1.0; // One year until expiry
// Then we calculate the call/put values via Monte Carlo
double call = monte_carlo_call_price(num_sims, S, K, r, v, T);
double put = monte_carlo_put_price(num_sims, S, K, r, v, T);
// Finally we output the parameters and prices
std::cout << "Number of Paths: " << num_sims << std::endl;
std::cout << "Underlying: " << S << std::endl;
std::cout << "Strike: " << K << std::endl;
std::cout << "Risk-Free Rate: " << r << std::endl;
std::cout << "Volatility: " << v << std::endl;
std::cout << "Maturity: " << T << std::endl;
std::cout << "Call Price: " << call << std::endl;
std::cout << "Put Price: " << put << std::endl;
return 0;
}
As alterações que fiz pareciam aumentar o tempo de execução do código em um segundo, mas não sei ao certo o que posso alterar para interromper o pipeline sem adicionar código. Um ponto na direção certa seria incrível, agradeço qualquer respost
Update: o professor que deu essa tarefa postou alguns detalhesOs destaques são:
É uma aula de arquitetura do segundo semestre de uma faculdade comunitária (usando o livro de Hennessy e Pattersons computadores de laboratório têm CPUs HasweOs alunos foram expostos aoCPUID
nstruções @ e como determinar o tamanho do cache, bem como intrínsecas e as instruçõesCLFLUSH
instrução. quaisquer opções do compilador são permitidas, assim como asm inlinEscrevendo seu próprio algoritmo de raiz quadrada foi anunciado como estando fora do claros comentários de @ Cowmoogun no meta thread indicam quenão estava claro que otimizações do compilador poderiam fazer parte disso, e assumiu-O0
, e que um aumento de 17% no tempo de execução era razoáve
arece que o objetivo da tarefa era fazer com que os alunos reordenassem o trabalho existente para reduzir o paralelismo no nível das instruções ou coisas assim, mas não é uma coisa ruim que as pessoas tenham se aprofundado e aprendido mai
Lembre-se de que esta é uma questão de arquitetura de computador, não uma questão sobre como tornar o C ++ lento em gera