multiple_regression.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /* StarPU --- Runtime system for heterogeneous multicore architectures.
  2. *
  3. * Copyright (C) 2016,2017 Inria
  4. * Copyright (C) 2018 Umeà University
  5. * Copyright (C) 2010,2011,2016,2017,2019 CNRS
  6. * Copyright (C) 2009-2011,2015-2018 Université de Bordeaux
  7. *
  8. * StarPU is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation; either version 2.1 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * StarPU is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. *
  17. * See the GNU Lesser General Public License in COPYING.LGPL for more details.
  18. */
  19. /* Code for computing multiple linear regression */
  20. #include <core/perfmodel/multiple_regression.h>
  21. typedef long int integer;
  22. typedef double doublereal;
  23. #ifdef STARPU_MLR_MODEL
  24. #ifdef STARPU_BUILT_IN_MIN_DGELS
  25. int _starpu_dgels_(char *trans, integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *work, integer *lwork, integer *info);
  26. #else
  27. int dgels_(char *trans, integer *m, integer *n, integer *nrhs, doublereal *a, integer *lda, doublereal *b, integer *ldb, doublereal *work, integer *lwork, integer *info);
  28. #endif
  29. #endif //STARPU_MLR_MODEL
  30. static unsigned long count_file_lines(FILE *f)
  31. {
  32. unsigned long lines=0;
  33. while(!feof(f))
  34. {
  35. int ch = fgetc(f);
  36. if(ch == '\n')
  37. {
  38. lines++;
  39. }
  40. }
  41. rewind(f);
  42. return lines;
  43. }
  44. static void dump_multiple_regression_list(double *mpar, double *my, int start, unsigned nparameters, struct starpu_perfmodel_history_list *list_history)
  45. {
  46. struct starpu_perfmodel_history_list *ptr = list_history;
  47. int i = start;
  48. unsigned j;
  49. while (ptr)
  50. {
  51. my[i] = ptr->entry->duration;
  52. for(j=0; j<nparameters; j++)
  53. mpar[i*nparameters+j] = ptr->entry->parameters[j];
  54. ptr = ptr->next;
  55. i++;
  56. }
  57. }
  58. static void load_old_calibration(double *mx, double *my, unsigned nparameters, char *filepath)
  59. {
  60. char buffer[1024];
  61. char *line;
  62. int i=0;
  63. FILE *f = fopen(filepath, "a+");
  64. STARPU_ASSERT_MSG(f, "Could not load performance model from file %s\n", filepath);
  65. line = fgets(buffer,sizeof(buffer),f);//skipping first line
  66. STARPU_ASSERT(line);
  67. while((line=fgets(buffer,sizeof(buffer),f))!=NULL)
  68. {
  69. char *record = strtok(line,",");
  70. STARPU_ASSERT_MSG(record, "Could not load performance model from file %s\n", filepath);
  71. my[i] = atof(record);
  72. record = strtok(NULL,",");
  73. int j=0;
  74. while(record != NULL)
  75. {
  76. mx[i*nparameters+j] = atof(record) ;
  77. ++j;
  78. record = strtok(NULL,",");
  79. }
  80. ++i ;
  81. }
  82. fclose(f);
  83. }
  84. static unsigned long find_long_list_size(struct starpu_perfmodel_history_list *list_history)
  85. {
  86. long cnt = 0;
  87. struct starpu_perfmodel_history_list *ptr = list_history;
  88. while (ptr)
  89. {
  90. cnt++;
  91. ptr = ptr->next;
  92. }
  93. return cnt;
  94. }
  95. #ifdef STARPU_MLR_MODEL
  96. int dgels_multiple_reg_coeff(double *mpar, double *my, unsigned long nn, unsigned ncoeff, unsigned nparameters, double *coeff, unsigned **combinations)
  97. {
  98. /* Arguments */
  99. /* ========= */
  100. /* TRANS (input) CHARACTER*1 */
  101. /* = 'N': the linear system involves A; */
  102. /* = 'T': the linear system involves A**T. */
  103. /* M (input) INTEGER */
  104. /* The number of rows of the matrix A. M >= 0. */
  105. /* N (input) INTEGER */
  106. /* The number of columns of the matrix A. N >= 0. */
  107. /* NRHS (input) INTEGER */
  108. /* The number of right hand sides, i.e., the number of */
  109. /* columns of the matrices B and X. NRHS >=0. */
  110. /* A (input/output) DOUBLE PRECISION array, dimension (LDA,N) */
  111. /* On entry, the M-by-N matrix A. */
  112. /* On exit, */
  113. /* if M >= N, A is overwritten by details of its QR */
  114. /* factorization as returned by DGEQRF; */
  115. /* if M < N, A is overwritten by details of its LQ */
  116. /* factorization as returned by DGELQF. */
  117. /* LDA (input) INTEGER */
  118. /* The leading dimension of the array A. LDA >= max(1,M). */
  119. /* B (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS) */
  120. /* On entry, the matrix B of right hand side vectors, stored */
  121. /* columnwise; B is M-by-NRHS if TRANS = 'N', or N-by-NRHS */
  122. /* if TRANS = 'T'. */
  123. /* On exit, if INFO = 0, B is overwritten by the solution */
  124. /* vectors, stored columnwise: */
  125. /* if TRANS = 'N' and m >= n, rows 1 to n of B contain the least */
  126. /* squares solution vectors; the residual sum of squares for the */
  127. /* solution in each column is given by the sum of squares of */
  128. /* elements N+1 to M in that column; */
  129. /* if TRANS = 'N' and m < n, rows 1 to N of B contain the */
  130. /* minimum norm solution vectors; */
  131. /* if TRANS = 'T' and m >= n, rows 1 to M of B contain the */
  132. /* minimum norm solution vectors; */
  133. /* if TRANS = 'T' and m < n, rows 1 to M of B contain the */
  134. /* least squares solution vectors; the residual sum of squares */
  135. /* for the solution in each column is given by the sum of */
  136. /* squares of elements M+1 to N in that column. */
  137. /* LDB (input) INTEGER */
  138. /* The leading dimension of the array B. LDB >= MAX(1,M,N). */
  139. /* WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) */
  140. /* On exit, if INFO = 0, WORK(1) returns the optimal LWORK. */
  141. /* LWORK (input) INTEGER */
  142. /* The dimension of the array WORK. */
  143. /* LWORK >= max( 1, MN + max( MN, NRHS ) ). */
  144. /* For optimal performance, */
  145. /* LWORK >= max( 1, MN + max( MN, NRHS )*NB ). */
  146. /* where MN = min(M,N) and NB is the optimum block size. */
  147. /* If LWORK = -1, then a workspace query is assumed; the routine */
  148. /* only calculates the optimal size of the WORK array, returns */
  149. /* this value as the first entry of the WORK array, and no error */
  150. /* message related to LWORK is issued by XERBLA. */
  151. /* INFO (output) INTEGER */
  152. /* = 0: successful exit */
  153. /* < 0: if INFO = -i, the i-th argument had an illegal value */
  154. /* > 0: if INFO = i, the i-th diagonal element of the */
  155. /* triangular factor of A is zero, so that A does not have */
  156. /* full rank; the least squares solution could not be */
  157. /* computed. */
  158. /* ===================================================================== */
  159. if(nn <= ncoeff)
  160. {
  161. _STARPU_DISP("Warning: This function is not intended for the use when number of parameters is larger than the number of observations. Check how your matrices A and B were allocated or simply add more benchmarks.\n Multiple linear regression model will not be written into perfmodel file.\n");
  162. return 1;
  163. }
  164. char trans = 'N';
  165. integer m = nn;
  166. integer n = ncoeff;
  167. integer nrhs = 1; // number of columns of B and X (wich are vectors therefore nrhs=1)
  168. doublereal *X;
  169. _STARPU_MALLOC(X, sizeof(double)*n*m); // (/!\ modified at the output) contain the model and the different values of pararmters
  170. doublereal *Y;
  171. _STARPU_MALLOC(Y, sizeof(double)*m);
  172. double coefficient;
  173. int i, j;
  174. unsigned k;
  175. for (i=0; i < m; i++)
  176. {
  177. Y[i] = my[i];
  178. X[i] = 1.;
  179. for (j=1; j < n; j++)
  180. {
  181. coefficient = 1.;
  182. for(k=0; k < nparameters; k++)
  183. {
  184. coefficient *= pow(mpar[i*nparameters+k],combinations[j-1][k]);
  185. }
  186. X[i+j*m] = coefficient;
  187. }
  188. }
  189. integer lda = m;
  190. integer ldb = m; //
  191. integer info = 0;
  192. integer lwork = n*2;
  193. doublereal *work; // (output)
  194. _STARPU_MALLOC(work, sizeof(double)*lwork);
  195. /* // Running LAPACK dgels_ */
  196. #ifdef STARPU_BUILT_IN_MIN_DGELS
  197. _starpu_dgels_(&trans, &m, &n, &nrhs, X, &lda, Y, &ldb, work, &lwork, &info);
  198. #else
  199. dgels_(&trans, &m, &n, &nrhs, X, &lda, Y, &ldb, work, &lwork, &info);
  200. #endif
  201. /* Check for the full rank */
  202. if( info != 0 )
  203. {
  204. _STARPU_DISP("Warning: Problems when executing dgels_ function. It seems like the diagonal element %ld is zero.\n Multiple linear regression model will not be written into perfmodel file.\n", info);
  205. return 1;
  206. }
  207. /* Copy computed coefficients */
  208. for(i=0; i<(int) ncoeff; i++)
  209. coeff[i] = Y[i];
  210. free(X);
  211. free(Y);
  212. free(work);
  213. return 0;
  214. }
  215. #endif //STARPU_MLR_MODEL
  216. /*
  217. Validating the accuracy of the coefficients.
  218. For the the validation is extremely basic, but it should be improved.
  219. */
  220. void starpu_validate_mlr(double *coeff, unsigned ncoeff, const char *codelet_name)
  221. {
  222. unsigned i;
  223. if (coeff[0] < 0)
  224. _STARPU_DISP("Warning: Constant computed by least square method is negative (%f). The model %s is likely to be inaccurate.\n", coeff[0], codelet_name);
  225. for(i=1; i<ncoeff; i++)
  226. if(fabs(coeff[i]) < 1E-10)
  227. _STARPU_DISP("Warning: Coefficient computed by least square method is extremelly small (%f). The model %s is likely to be inaccurate.\n", coeff[i], codelet_name);
  228. }
  229. int _starpu_multiple_regression(struct starpu_perfmodel_history_list *ptr, double *coeff, unsigned ncoeff, unsigned nparameters, const char **parameters_names, unsigned **combinations, const char *codelet_name)
  230. {
  231. unsigned long i;
  232. unsigned j;
  233. /* Computing number of rows */
  234. unsigned n=find_long_list_size(ptr);
  235. /* Reading old calibrations if necessary */
  236. FILE *f=NULL;
  237. char directory[300];
  238. snprintf(directory, sizeof(directory), "%s/.starpu/sampling/codelets/tmp", _starpu_get_home_path());
  239. _starpu_mkpath_and_check(directory, S_IRWXU);
  240. char filepath[400];
  241. snprintf(filepath, sizeof(filepath), "%s/%s.out", directory,codelet_name);
  242. unsigned long old_lines=0;
  243. int calibrate = _starpu_get_calibrate_flag();
  244. if (calibrate==1)
  245. {
  246. f = fopen(filepath, "a+");
  247. STARPU_ASSERT_MSG(f, "Could not save performance model into the file %s\n", filepath);
  248. old_lines=count_file_lines(f);
  249. /* If the program is run for the first time the old_lines will be 0 */
  250. //STARPU_ASSERT(old_lines);
  251. n+=old_lines;
  252. fclose(f);
  253. }
  254. /* Allocating X and Y matrices */
  255. double *mpar;
  256. _STARPU_MALLOC(mpar, nparameters*n*sizeof(double));
  257. double *my;
  258. _STARPU_MALLOC(my, n*sizeof(double));
  259. /* Loading old calibration */
  260. if (calibrate==1 && old_lines > 0)
  261. load_old_calibration(mpar, my, nparameters, filepath);
  262. /* Filling X and Y matrices with measured values */
  263. dump_multiple_regression_list(mpar, my, old_lines, nparameters, ptr);
  264. if (ncoeff!=0 && combinations!=NULL)
  265. {
  266. #ifdef STARPU_MLR_MODEL
  267. /* Computing coefficients using multiple linear regression */
  268. if(dgels_multiple_reg_coeff(mpar, my, n, ncoeff, nparameters, coeff, combinations))
  269. {
  270. free(mpar);
  271. free(my);
  272. return 1;
  273. }
  274. /* Basic validation of the model accuracy */
  275. starpu_validate_mlr(coeff, ncoeff, codelet_name);
  276. #else
  277. _STARPU_DISP("Warning: StarPU was compiled with '--disable-mlr' option or on Windows machine, thus multiple linear regression model will not be computed.\n");
  278. for(i=0; i<ncoeff; i++)
  279. coeff[i] = 0.;
  280. #endif //STARPU_MLR_MODEL
  281. }
  282. /* Preparing new output calibration file */
  283. if (calibrate==1 || calibrate==2)
  284. {
  285. if (old_lines > 0)
  286. {
  287. f = fopen(filepath, "a+");
  288. STARPU_ASSERT_MSG(f, "Could not save performance model into the file %s\n", filepath);
  289. }
  290. else
  291. {
  292. f = fopen(filepath, "w+");
  293. STARPU_ASSERT_MSG(f, "Could not save performance model into the file %s\n", filepath);
  294. fprintf(f, "Duration");
  295. for(j=0; j<nparameters; j++)
  296. {
  297. if(parameters_names != NULL && parameters_names[j]!= NULL)
  298. fprintf(f, ", %s", parameters_names[j]);
  299. else
  300. fprintf(f, ", P%u", j);
  301. }
  302. }
  303. }
  304. /* Writing parameters to calibration file */
  305. if (calibrate==1 || calibrate==2)
  306. {
  307. for(i=old_lines; i<n; i++)
  308. {
  309. fprintf(f, "\n%f", my[i]);
  310. for(j=0; j<nparameters; j++)
  311. fprintf(f, ", %f", mpar[i*nparameters+j]);
  312. }
  313. fclose(f);
  314. }
  315. /* Cleanup */
  316. free(mpar);
  317. free(my);
  318. return 0;
  319. }