12.1.4.3 : Le main.cpp avec des indices



Comme les std::transform ne peuvent expimer que des calculs triadiques, il va falloir ruser un peu. L'autre difficulté est que les vecteurs qui contiennent les données ce calibration sont plus petits que le vecteur de données que l'on veut analyser, c'est un broadcast noteQui existe en C++ mais que pour les registres vectoriels..

Un des paramètres sera donc un vecteur d'indices qui permettront de lire les bonnes données de calibration en fonction des données à calibrer.

On commence avec les includes standards :
1
2
3
4
5
6
7
8
#include <iostream>
#include <vector>
#include <numeric>

#include <execution>
#include <algorithm>

#include "micro_benchmark.h"


On déclare notre kernel :
1
2
3
4
5
6
7
8
9
10
11
///Compute the calibration
/**	@param[out] vecCalibSignal : vector of calibrated signal
 * 	@param tabADC : pointer to the table of ADC values
 * 	@param tabPed : pointer to the table of pedestal
 * 	@param tabGain : pointer to the table of gain
 * 	@param vecIdx : vector of index to be used to round robin over the pixel
 * 	@param nbPixel : number of pixels in the camera
*/
void compute_calibration(std::vector<float> & vecCalibSignal,
			const float * tabADC, const float * tabPed, const float* tabGain, const std::vector<int> & vecIdx, int nbPixel)
{


La méthode d'exécution sera définie par la macro EXECUTION_POLICY comme ceci nous pourrons compiler la même source avec plusieurs méthodes :
1
2
	std::transform(EXECUTION_POLICY, std::begin(vecIdx), std::end(vecIdx), std::begin(vecCalibSignal),
		[=](int i){


Il faut passer notre tableau d'indices pour récupérer les bonnes valeurs de tabPed et tabGain :
1
2
3
4
			unsigned int idxPedGain = i % nbPixel;	//Prevent read of vecGain and vecPedestal outside of the bound
			return (tabADC[i] - tabPed[idxPedGain])*tabGain[idxPedGain];
	});
}


La fonction qui évaluera notre kernel :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
///Get the number of nanoseconds per elements of the Calibration
/**	@param nbPixel : number of pixels of the tables
*/
void evaluateCalibration(size_t nbPixel){
	//Let's define size of data :
	size_t nbEvent(NB_EVENT), nbSlice(NB_SLICE);
	size_t nbElement(nbEvent*nbSlice*nbPixel);
	std::vector<float> vecGain(nbPixel), vecPedestal(nbPixel);
	std::fill(vecGain.begin(), vecGain.end(), 0.02f);
	std::fill(vecPedestal.begin(), vecPedestal.end(), 40.0f);
	
	std::vector<float> vecADCSignal(nbElement), vecCalibSignal(nbElement);
	std::fill(vecADCSignal.begin(), vecADCSignal.end(), 42.0f);
	
	std::vector<int> vecIdx(nbElement);		//Init vector of index for the computation
	std::iota(vecIdx.begin(), vecIdx.end(), 0);	//Hope some day views will work to avoid allocation of index vector
	
	//We have to create pointer to be able to catch them by copy without losing any time
	float * tabADC = vecADCSignal.data(), *tabGain = vecGain.data(), *tabPed = vecPedestal.data();
	size_t fullNbElement(nbElement);
	micro_benchmarkAutoNsPrint("evaluateCalibration", fullNbElement, compute_calibration, vecCalibSignal, tabADC, tabPed, tabGain, vecIdx, nbPixel);
}


Enfin, nous appellons la fonction d'évaluation de MicroBenchmark :

1
2
3
int main(int argc, char** argv){
	return micro_benchmarkParseArg(argc, argv, evaluateCalibration);
}


Le fichier main.cpp complet :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/***************************************
	Auteur : Pierre Aubert
	Mail : pierre.aubert@lapp.in2p3.fr
	Licence : CeCILL-C
****************************************/
#include <iostream>
#include <vector>
#include <numeric>

#include <execution>
#include <algorithm>

#include "micro_benchmark.h"

///Compute the calibration
/**	@param[out] vecCalibSignal : vector of calibrated signal
 * 	@param tabADC : pointer to the table of ADC values
 * 	@param tabPed : pointer to the table of pedestal
 * 	@param tabGain : pointer to the table of gain
 * 	@param vecIdx : vector of index to be used to round robin over the pixel
 * 	@param nbPixel : number of pixels in the camera
*/
void compute_calibration(std::vector<float> & vecCalibSignal,
			const float * tabADC, const float * tabPed, const float* tabGain, const std::vector<int> & vecIdx, int nbPixel)
{
	std::transform(EXECUTION_POLICY, std::begin(vecIdx), std::end(vecIdx), std::begin(vecCalibSignal),
		[=](int i){
			unsigned int idxPedGain = i % nbPixel;	//Prevent read of vecGain and vecPedestal outside of the bound
			return (tabADC[i] - tabPed[idxPedGain])*tabGain[idxPedGain];
	});
}

///Get the number of nanoseconds per elements of the Calibration
/**	@param nbPixel : number of pixels of the tables
*/
void evaluateCalibration(size_t nbPixel){
	//Let's define size of data :
	size_t nbEvent(NB_EVENT), nbSlice(NB_SLICE);
	size_t nbElement(nbEvent*nbSlice*nbPixel);
	std::vector<float> vecGain(nbPixel), vecPedestal(nbPixel);
	std::fill(vecGain.begin(), vecGain.end(), 0.02f);
	std::fill(vecPedestal.begin(), vecPedestal.end(), 40.0f);
	
	std::vector<float> vecADCSignal(nbElement), vecCalibSignal(nbElement);
	std::fill(vecADCSignal.begin(), vecADCSignal.end(), 42.0f);
	
	std::vector<int> vecIdx(nbElement);		//Init vector of index for the computation
	std::iota(vecIdx.begin(), vecIdx.end(), 0);	//Hope some day views will work to avoid allocation of index vector
	
	//We have to create pointer to be able to catch them by copy without losing any time
	float * tabADC = vecADCSignal.data(), *tabGain = vecGain.data(), *tabPed = vecPedestal.data();
	size_t fullNbElement(nbElement);
	micro_benchmarkAutoNsPrint("evaluateCalibration", fullNbElement, compute_calibration, vecCalibSignal, tabADC, tabPed, tabGain, vecIdx, nbPixel);
}

int main(int argc, char** argv){
	return micro_benchmarkParseArg(argc, argv, evaluateCalibration);
}
Le fichier main.cpp est disponible ici.