doc: Add serial to list of ci file reserved words
[charm.git] / src / conv-core / memoryaffinity.c
1 /**
2   * Considering the effect of memory affinity on the performance
3   * for the NUMA nodes.
4   *
5   * Author: Christiane Pousa Ribeiro
6   * LIG - INRIA - MESCAL
7   * April, 2010
8   *
9   * Modified and integrated into Charm++ by Chao Mei
10   * May, 2010
11   */
12
13 #include "converse.h"
14 #include "sockRoutines.h"
15 #define DEBUGP(x)  /* CmiPrintf x;  */
16 CpvExtern(int, myCPUAffToCore);
17 #if CMK_HAS_NUMACTRL
18 #define _GNU_SOURCE
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <unistd.h>
22 #include <linux/mempolicy.h>
23 #include <numaif.h>
24 #include <numa.h>
25 #include <string.h>
26 #include <sched.h>
27 #include <math.h>
28 typedef unsigned long mem_aff_mask;
29 static void MEM_MASK_ZERO(mem_aff_mask *mem_mask) {
30     memset(mem_mask, 0, sizeof(mem_aff_mask));
31 }
32 static void MEM_MASK_SET(int nid, mem_aff_mask *mem_mask) {
33     *mem_mask = *mem_mask | (1<<nid);
34 }
35 static void MEM_MASK_CLEAR(int nid, mem_aff_mask *mem_mask) {
36     *mem_mask = *mem_mask & (~(1<<nid));
37 }
38 int print_mem_affinity() {
39     mem_aff_mask mask;
40     unsigned int len = 8*sizeof(mask);
41     char spol[16];
42     int policy;
43     spol[0]='\0';
44     /* Memory policy to the current process */
45     if ((get_mempolicy(&policy,&mask,len,0,0)) < 0) {
46         perror("mem_getaffinity");
47         return -1;
48     }
49     if (policy == MPOL_INTERLEAVE)
50         strcpy(spol,"INTERLEAVE");
51     else if (policy == MPOL_BIND)
52         strcpy(spol,"BIND");
53     else
54         strcpy(spol,"PREFERRED");
55     CmiPrintf("%d: Mem affinity mask is: %08lx with policy %s\n", CmiMyPe(),mask,spol);
56     return 0;
57 }
58 static int CmiNumNUMANodes(void) {
59     FILE *fp_nodes;
60     int max_node=-1;
61     char command[]="ls -1d /sys/devices/system/node/node*|wc|awk '{print $1}'";
62     fp_nodes = popen(command,"r");
63     fscanf(fp_nodes,"%d",&max_node);
64     pclose(fp_nodes);
65     return max_node;
66 }
67 static int getNUMANidByRank(int coreid) {
68     int i;
69     /*int totalCores = CmiNumCores();*/
70     int totalNUMANodes = CmiNumNUMANodes();
71     /*The core id array is viewed as 2D array but in form of 1D array*/
72     /*int *coreids=(int *)malloc(sizeof(int)*totalCores);*/
73     /*Assume each NUMA node has the same number of cores*/
74     /*int nCoresPerNode = totalCores/totalNUMANodes;*/
75     /*CmiAssert(totalCores%totalNUMANodes==0);*/
76     char command[256];
77     for (i=0; i<totalNUMANodes; i++) {
78         FILE *cmd;
79         int cpuid;
80         sprintf(command, "ls -1d /sys/devices/system/node/node%d/cpu[0-9]* | cut -d'u' -f2", i);
81         cmd = popen(command, "r");
82         while (1) {
83             int ret=fscanf(cmd, "%d\n", &cpuid);
84             if (ret==EOF) break;
85             if (cpuid == coreid) {
86                 pclose(cmd);
87                 /*free(coreids);*/
88                 return i;
89             }
90         }
91         pclose(cmd);
92     }
93     /*free(coreids);*/
94     CmiPrintf("%d: the corresponding NUMA node for cpu id %d is not found!\n", CmiMyPe(), coreid);
95     CmiAssert(0);
96     return -1;
97 }
98
99 /**
100  * policy: indicates the memory policy
101  * nids: indicates the NUMA nodes to be applied
102  * len: indicates how many NUMA nodes nids has
103  */
104 int CmiSetMemAffinity(int policy, int *nids, int len) {
105     int i;
106     mem_aff_mask myMask;
107     unsigned int masksize = 8*sizeof(mem_aff_mask);
108     MEM_MASK_ZERO(&myMask);
109     for (i=0; i<len; i++) MEM_MASK_SET(nids[i], &myMask);
110     if (set_mempolicy(policy, &myMask, masksize)<0) {
111         CmiPrintf("Error> setting memory policy (%d) error with mask %X\n", policy, myMask);
112         return -1;
113     } else
114         return 0;
115 }
116 void CmiInitMemAffinity(char **argv) {
117
118     int i;
119     int policy=-1;
120     /*step1: parsing args maffinity, mempol and nodemap (nodemap is optional)*/
121     int maffinity_flag = CmiGetArgFlagDesc(argv, "+maffinity", "memory affinity");
122     /*the node here refers to the nodes that are seen by libnuma on a phy node*/
123     /*nodemap is a string of ints separated by ","*/
124     char *nodemap = NULL;
125
126     char *mpol = NULL;
127     CmiGetArgStringDesc(argv, "+memnodemap", &nodemap, "define memory node mapping");
128     CmiGetArgStringDesc(argv, "+mempol", &mpol, "define memory policy {bind, preferred or interleave} ");
129
130
131     if (!maffinity_flag) return;
132
133     /*Currently skip the communication thread*/
134     /**
135       * Note: the cpu affinity of comm thread may not be set
136       * if "commap" is not specified. This is why the following
137       * code regarding the comm thd needs to be put before
138       * the codes that checks whether cpu affinity is set
139       * or not
140       */
141     if (CmiMyPe() >= CmiNumPes()) {
142         CmiNodeAllBarrier();
143         return;
144     }
145
146     /*step2: checking whether the required cpu affinity has been set*/
147     if (CpvInitialized(myCPUAffToCore) && CpvAccess(myCPUAffToCore)==-1) {
148         if (CmiMyPe()==0)
149             CmiPrintf("Charm++> memory affinity disabled because cpu affinity is not enabled!\n");
150         CmiNodeAllBarrier();
151         return;
152     }
153
154     if (CmiMyPe()==0) {
155         CmiPrintf("Charm++> memory affinity enabled! \n");
156     }
157
158     /*Select memory policy*/
159     if (mpol==NULL) {
160         CmiAbort("Memory policy must be specified!\n");
161     }
162     if (strcmp(mpol, "interleave")==0) policy = MPOL_INTERLEAVE;
163     else if (strcmp(mpol, "preferred")==0) policy = MPOL_PREFERRED;
164     else if (strcmp(mpol, "bind")==0) policy = MPOL_BIND;
165     else {
166         CmiPrintf("Error> Invalid memory policy :%s\n", mpol);
167         CmiAbort("Invalid memory policy!");
168     }
169
170     /**
171      * step3: check whether nodemap is NULL or not
172      * step 3a): nodemap is not NULL
173      * step 3b): nodemap is NULL, set memory policy according to the result
174      * of cpu affinity settings.
175      */
176     if (nodemap!=NULL) {
177         int *nodemapArr = NULL;
178         int nodemapArrSize = 1;
179         int prevIntStart,j;
180         int curnid;
181         for (i=0; i<strlen((const char *)nodemap); i++) {
182             if (nodemap[i]==',') nodemapArrSize++;
183         }
184         nodemapArr = malloc(nodemapArrSize*sizeof(int));
185         prevIntStart=j=0;
186         for (i=0; i<strlen((const char *)nodemap); i++) {
187             if (nodemap[i]==',') {
188                 curnid = atoi(nodemap+prevIntStart);
189                 if (curnid >= CmiNumNUMANodes()) {
190                     CmiPrintf("Error> Invalid node number %d, only have %d nodes (0-%d) on the machine. \n", curnid, CmiNumNUMANodes(), CmiNumNUMANodes()-1);
191                     CmiAbort("Invalid node number!");
192                 }
193                 nodemapArr[j++] = curnid;
194                 prevIntStart=i+1;
195             }
196         }
197         /*record the last nid after the last comma*/
198         curnid = atoi(nodemap+prevIntStart);
199         if (curnid >= CmiNumNUMANodes()) {
200             CmiPrintf("Error> Invalid node number %d, only have %d nodes (0-%d) on the machine. \n", curnid, CmiNumNUMANodes(), CmiNumNUMANodes()-1);
201             CmiAbort("Invalid node number!");
202         }
203         nodemapArr[j] = curnid;
204
205         int myPhyRank = CpvAccess(myCPUAffToCore);
206         int myMemNid = nodemapArr[myPhyRank%nodemapArrSize];
207         int retval = -1;
208         if (policy==MPOL_INTERLEAVE) {
209             retval = CmiSetMemAffinity(policy, nodemapArr, nodemapArrSize);
210         } else {
211             retval = CmiSetMemAffinity(policy, &myMemNid, 1);
212         }
213         if (retval<0) {
214             CmiAbort("set_mempolicy error w/ mem nodemap");
215         }
216     } else {
217         /*use the affinity map set by the cpu affinity*/
218         int myPhyRank = CpvAccess(myCPUAffToCore);
219         /*get the NUMA node id from myPhyRank (a core id)*/
220         int myMemNid = getNUMANidByRank(myPhyRank);
221
222         int retval=-1;
223         if (policy==MPOL_INTERLEAVE) {
224             int totalNUMANodes = CmiNumNUMANodes();
225             int *nids = (int *)malloc(totalNUMANodes*sizeof(int));
226             for (i=0; i<totalNUMANodes; i++) nids[i] = i;
227             retval = CmiSetMemAffinity(policy, nids, totalNUMANodes);
228             free(nids);
229         } else {
230             retval = CmiSetMemAffinity(policy, &myMemNid, 1);
231         }
232         if (retval<0) {
233             CmiAbort("set_mempolicy error w/o mem nodemap");
234         }
235     }
236
237     /*print_mem_affinity();*/
238     CmiNodeAllBarrier();
239 }
240 #else
241 void CmiInitMemAffinity(char **argv) {
242     char *tmpstr = NULL;
243     int maffinity_flag = CmiGetArgFlagDesc(argv,"+maffinity",
244                                            "memory affinity");
245     if (maffinity_flag && CmiMyPe()==0)
246         CmiPrintf("memory affinity is not supported, +maffinity flag disabled.\n");
247
248     /* consume the remaining possible arguments */
249     CmiGetArgStringDesc(argv, "+memnodemap", &tmpstr, "define memory node mapping");
250     CmiGetArgStringDesc(argv, "+mempol", &tmpstr, "define memory policy {bind, preferred or interleave} ");
251 }
252 #endif
253