~ubuntu-branches/ubuntu/utopic/nwchem/utopic

« back to all changes in this revision

Viewing changes to src/tools/ga-5-1/armci/src-portals/mutex.c

  • Committer: Package Import Robot
  • Author(s): Michael Banck, Daniel Leidert, Andreas Tille, Michael Banck
  • Date: 2013-07-04 12:14:55 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20130704121455-5tvsx2qabor3nrui
Tags: 6.3-1
* New upstream release.
* Fixes anisotropic properties (Closes: #696361).
* New features include:
  + Multi-reference coupled cluster (MRCC) approaches
  + Hybrid DFT calculations with short-range HF 
  + New density-functionals including Minnesota (M08, M11) and HSE hybrid
    functionals
  + X-ray absorption spectroscopy (XAS) with TDDFT
  + Analytical gradients for the COSMO solvation model
  + Transition densities from TDDFT 
  + DFT+U and Electron-Transfer (ET) methods for plane wave calculations
  + Exploitation of space group symmetry in plane wave geometry optimizations
  + Local density of states (LDOS) collective variable added to Metadynamics
  + Various new XC functionals added for plane wave calculations, including
    hybrid and range-corrected ones
  + Electric field gradients with relativistic corrections 
  + Nudged Elastic Band optimization method
  + Updated basis sets and ECPs 

[ Daniel Leidert ]
* debian/watch: Fixed.

[ Andreas Tille ]
* debian/upstream: References

[ Michael Banck ]
* debian/upstream (Name): New field.
* debian/patches/02_makefile_flags.patch: Refreshed.
* debian/patches/06_statfs_kfreebsd.patch: Likewise.
* debian/patches/07_ga_target_force_linux.patch: Likewise.
* debian/patches/05_avoid_inline_assembler.patch: Removed, no longer needed.
* debian/patches/09_backported_6.1.1_fixes.patch: Likewise.
* debian/control (Build-Depends): Added gfortran-4.7 and gcc-4.7.
* debian/patches/10_force_gcc-4.7.patch: New patch, explicitly sets
  gfortran-4.7 and gcc-4.7, fixes test suite hang with gcc-4.8 (Closes:
  #701328, #713262).
* debian/testsuite: Added tests for COSMO analytical gradients and MRCC.
* debian/rules (MRCC_METHODS): New variable, required to enable MRCC methods.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#if HAVE_CONFIG_H
2
 
#   include "config.h"
3
 
#endif
4
 
 
5
 
#if HAVE_STDIO_H
6
 
#   include <stdio.h>
7
 
#endif
8
 
 
9
 
/* $Id: mutex.c,v 1.24.10.1 2006-12-21 23:50:48 manoj Exp $ */
10
 
#include "armcip.h"
11
 
#include "copy.h"
12
 
#include "parmci.h"
13
 
#include "request.h"
14
 
 
15
 
#define DEBUG 0
16
 
#define MAX_LOCKS 32768
17
 
#define SPINMAX 1000
18
 
 
19
 
#if defined(LAPI) || defined(GM)
20
 
#  define SERVER_LOCK 
21
 
#endif
22
 
 
23
 
double _dummy_work_=0.;
24
 
#ifdef LAPI /*fix to if cmpl handler for a pending unlock runs after destroy*/
25
 
int mymutexcount;
26
 
double _dummy_server_work_=0.;
27
 
#endif
28
 
static int num_mutexes=0, *tickets; 
29
 
 
30
 
typedef struct {
31
 
       int mutex;
32
 
       int turn;
33
 
       msg_tag_t tag;
34
 
} waiting_list_t;
35
 
 
36
 
 
37
 
/* data structure to store info about blocked (waiting) process for mutex */
38
 
static waiting_list_t* blocked=(waiting_list_t*)0; 
39
 
 
40
 
 
41
 
typedef struct {
42
 
int* token;
43
 
int* turn;
44
 
int* tickets;
45
 
int count;
46
 
} mutex_entry_t;
47
 
 
48
 
void** mutex_mem_ar;
49
 
mutex_entry_t *glob_mutex;
50
 
 
51
 
 
52
 
int PARMCI_Create_mutexes(int num)
53
 
{
54
 
int rc,p, totcount;
55
 
int *mutex_count = (int*)armci_internal_buffer;
56
 
 
57
 
  if((sizeof(int)*armci_nproc) > armci_getbufsize()){
58
 
    mutex_count = (double *)malloc(sizeof(int)*armci_nproc);
59
 
  }
60
 
        if (num < 0 || num > MAX_LOCKS) return(FAIL);
61
 
  if(num_mutexes) armci_die("mutexes already created",num_mutexes);
62
 
 
63
 
  if(armci_nproc == 1){  num_mutexes=1; return(0); }
64
 
 
65
 
  /* local memory allocation for mutex arrays*/
66
 
  mutex_mem_ar = (void*) malloc(armci_nproc*sizeof(void*));
67
 
  if(!mutex_mem_ar) armci_die("ARMCI_Create_mutexes: malloc failed",0);
68
 
    glob_mutex = (void*)malloc(armci_nproc*sizeof(mutex_entry_t));
69
 
  if(!glob_mutex){
70
 
    free(mutex_mem_ar);
71
 
    armci_die("ARMCI_Create_mutexes: malloc 2 failed",0);
72
 
  }
73
 
 
74
 
           
75
 
/*        bzero(mutex_count,armci_nproc*sizeof(int));*/
76
 
  bzero((char*)mutex_count,sizeof(int)*armci_nproc);
77
 
 
78
 
        /* find out how many mutexes everybody allocated */
79
 
        mutex_count[armci_me]=num;
80
 
        armci_msg_igop(mutex_count, armci_nproc, "+");
81
 
        for(p=totcount=0; p< armci_nproc; p++)totcount+=mutex_count[p];
82
 
 
83
 
        tickets = calloc(totcount,sizeof(int));
84
 
        if(!tickets) {
85
 
           free(glob_mutex);
86
 
           free(mutex_mem_ar);
87
 
           return(FAIL2);
88
 
        }
89
 
 
90
 
        /* we need memory for token and turn - 2 ints */
91
 
        rc = PARMCI_Malloc(mutex_mem_ar,2*num*sizeof(int));
92
 
        if(rc){
93
 
           free(glob_mutex);
94
 
           free(mutex_mem_ar);
95
 
           free(tickets);
96
 
           return(FAIL3);
97
 
        }
98
 
 
99
 
        if(num)bzero((char*)mutex_mem_ar[armci_me],2*num*sizeof(int));
100
 
 
101
 
        /* setup global mutex array */
102
 
        for(p=totcount=0; p< armci_nproc; p++){
103
 
           glob_mutex[p].token   = mutex_mem_ar[p];
104
 
           glob_mutex[p].turn    = glob_mutex[p].token + mutex_count[p];
105
 
           glob_mutex[p].count   = mutex_count[p];
106
 
           glob_mutex[p].tickets = tickets + totcount;
107
 
           totcount += mutex_count[p];
108
 
        }
109
 
 
110
 
        num_mutexes= totcount;
111
 
#ifdef LAPI
112
 
        mymutexcount = num;
113
 
#endif
114
 
        PARMCI_Barrier();
115
 
 
116
 
        if(DEBUG)
117
 
           fprintf(stderr,"%d created (%d,%d) mutexes\n",armci_me,num,totcount);
118
 
 
119
 
        return(0);
120
 
}
121
 
 
122
 
 
123
 
void armci_serv_mutex_create()
124
 
{
125
 
     int mem = armci_nproc*sizeof(waiting_list_t);
126
 
     blocked = (waiting_list_t*)malloc(mem);
127
 
     if(!blocked) armci_die("armci server:error allocating mutex memory ",0);
128
 
}
129
 
 
130
 
 
131
 
void armci_serv_mutex_close()
132
 
{
133
 
     if(blocked) free(blocked );
134
 
     blocked = (waiting_list_t*)0;
135
 
}
136
 
        
137
 
 
138
 
int PARMCI_Destroy_mutexes()
139
 
{
140
 
#ifdef LAPI /*fix to if cmpl handler for a pending unlock runs after destroy*/
141
 
     int proc, mutex, i,factor=0;
142
 
#endif
143
 
     if(num_mutexes==0)armci_die("armci_destroy_mutexes: not created",0);
144
 
     if(armci_nproc == 1) return(0);
145
 
 
146
 
     armci_msg_barrier();
147
 
 
148
 
#ifdef LAPI /*fix to if cmpl handler for a pending unlock runs after destroy*/
149
 
     for(proc=0;proc<armci_nproc;proc++){
150
 
          for(mutex=0;mutex<glob_mutex[proc].count;mutex++){
151
 
            _dummy_server_work_ = 0.; /* must be global to fool the compiler */
152
 
            while(!armci_mutex_free(mutex,proc)){
153
 
              for(i=0; i<  SPINMAX *factor; i++) _dummy_server_work_ += 1.;
154
 
              factor+=1;
155
 
            }
156
 
          } 
157
 
     }
158
 
#endif
159
 
     num_mutexes=0;
160
 
 
161
 
#    if defined(SERVER_LOCK)
162
 
        armci_serv_mutex_close();
163
 
#    endif
164
 
 
165
 
     if(glob_mutex[armci_me].count)PARMCI_Free(glob_mutex[armci_me].token);
166
 
 
167
 
     free(tickets);
168
 
     free(glob_mutex);
169
 
     free(mutex_mem_ar);
170
 
 
171
 
     return(0);
172
 
}
173
 
 
174
 
 
175
 
static int register_in_mutex_queue(int id, int proc)
176
 
{
177
 
int *mutex_entry, ticket;
178
 
 
179
 
    if(glob_mutex[proc].count < id)
180
 
       armci_die2("armci:invalid mutex id",id, glob_mutex[proc].count);
181
 
    mutex_entry = glob_mutex[proc].token  + id;
182
 
    PARMCI_Rmw(ARMCI_FETCH_AND_ADD, &ticket, mutex_entry, 1, proc);
183
 
 
184
 
    return ticket;
185
 
}
186
 
 
187
 
 
188
 
/*\ check if mutex is available by comparing turn and token
189
 
 *  can only be called by a process on the same SMP node as proc
190
 
\*/
191
 
static int armci_mutex_free(int mutex, int proc)
192
 
{
193
 
volatile int *mutex_ticket=glob_mutex[proc].turn + mutex;
194
 
volatile int *turn = glob_mutex[proc].token  +mutex;
195
 
 
196
 
      /* here we will put code to check if other processes on the node
197
 
       * are waiting for this mutex
198
 
       * lockinfo_node[me].ticket = mutex_ticket;
199
 
       * lockinfo_node[me].mutex  = mutex;
200
 
       */
201
 
 
202
 
       if(*mutex_ticket == *turn) return 1;
203
 
       else return 0;
204
 
}
205
 
 
206
 
 
207
 
 
208
 
static void armci_generic_lock(int mutex, int proc)
209
 
{
210
 
int i, myturn, factor=0, len=sizeof(int);
211
 
int  *mutex_ticket, next_in_line;
212
 
        
213
 
      mutex_ticket= glob_mutex[proc].turn + mutex;
214
 
      myturn = register_in_mutex_queue(mutex, proc);
215
 
 
216
 
      /* code to reduce cost of unlocking mutex on the same SMP node goes here
217
 
       * lockinfo_node[me].ticket = mutex_ticket;
218
 
       * lockinfo_node[me].mutex  = mutex;
219
 
       */
220
 
 
221
 
      _dummy_work_ = 0.; /* must be global to fool the compiler */
222
 
      do {
223
 
 
224
 
           PARMCI_Get(mutex_ticket, &next_in_line, len, proc);
225
 
           if(next_in_line > myturn)
226
 
              armci_die2("armci: problem with tickets",myturn,next_in_line); 
227
 
          
228
 
           /* apply a linear backoff delay before retrying  */
229
 
           for(i=0; i<  SPINMAX * factor; i++) _dummy_work_ += 1.;
230
 
 
231
 
           factor += 1;
232
 
 
233
 
      }while (myturn != next_in_line);
234
 
 
235
 
      glob_mutex[proc].tickets[mutex] = myturn; /* save ticket value */
236
 
}
237
 
 
238
 
 
239
 
static void armci_generic_unlock(int mutex, int proc)
240
 
{
241
 
int *mutex_ticket= glob_mutex[proc].turn + mutex;
242
 
int *newval = glob_mutex[proc].tickets +mutex;
243
 
int len=sizeof(int);
244
 
 
245
 
       /* update ticket for next process requesting this mutex */
246
 
       (*newval) ++; 
247
 
 
248
 
       /* write new ticket value stored previously in tickets  */
249
 
       PARMCI_Put(newval, mutex_ticket, len, proc);
250
 
       MEM_FENCE;
251
 
}
252
 
 
253
 
 
254
 
/*\  Acquire mutex  for "proc"
255
 
 *   -must be executed in hrecv/AM handler thread
256
 
 *   -application thread must use generic_lock routine
257
 
\*/
258
 
int armci_server_lock_mutex(int mutex, int proc, msg_tag_t tag)
259
 
{
260
 
int myturn;
261
 
int *mutex_ticket, next_in_line, len=sizeof(int);
262
 
int owner = armci_me;
263
 
        
264
 
 
265
 
      if(DEBUG)fprintf(stderr,"SLOCK=%d owner=%d p=%d m=%d\n",
266
 
                       armci_me,owner, proc,mutex);
267
 
 
268
 
      mutex_ticket= glob_mutex[owner].turn + mutex;
269
 
      myturn = register_in_mutex_queue(mutex, owner);
270
 
 
271
 
      armci_copy(mutex_ticket, &next_in_line, len);
272
 
 
273
 
      if(next_in_line > myturn)
274
 
         armci_die2("armci-s: problem with tickets",myturn,next_in_line); 
275
 
 
276
 
      if(next_in_line != myturn){
277
 
           if(!blocked)armci_serv_mutex_create();
278
 
           blocked[proc].mutex = mutex;
279
 
           blocked[proc].turn = myturn;
280
 
           blocked[proc].tag  = tag;
281
 
           if(DEBUG) fprintf(stderr,"SLOCK=%d proc=%d blocked (%d,%d)\n",
282
 
                                     armci_me, proc, next_in_line,myturn);
283
 
           return -1;
284
 
 
285
 
      } else {
286
 
 
287
 
           if(DEBUG) fprintf(stderr,"SLOCK=%d proc=%d sending ticket (%d)\n",
288
 
                                                       armci_me, proc, myturn);
289
 
 
290
 
           /* send ticket to requesting node */
291
 
           /* GA_SEND_REPLY(tag, &myturn, sizeof(int), proc); */
292
 
           return (myturn);
293
 
      } 
294
 
}
295
 
           
296
 
 
297
 
        
298
 
/*\  Release mutex "id" held by proc 
299
 
 *   called from hrecv/AM handler AND application thread
300
 
\*/
301
 
int armci_server_unlock_mutex(int mutex, int proc, int Ticket, msg_tag_t* ptag)
302
 
{
303
 
#define NOBODY -1
304
 
int owner = armci_me;
305
 
int i, p=NOBODY, *mutex_ticket= glob_mutex[owner].turn + mutex;
306
 
int len=sizeof(int);
307
 
 
308
 
     if(DEBUG) fprintf(stderr,"SUNLOCK=%d node=%d mutex=%d ticket=%d\n",
309
 
                       armci_me,proc,mutex,Ticket);
310
 
 
311
 
     Ticket++; 
312
 
     armci_copy(&Ticket, mutex_ticket, len);
313
 
 
314
 
     /* if mutex is free then nobody is reqistered in queue */
315
 
     if(armci_mutex_free(mutex, proc))  return -1;
316
 
 
317
 
     /* search for the next process in queue waiting for this mutex */
318
 
     for(i=0; i< armci_nproc; i++){
319
 
        if(!blocked)break; /* not allocated yet - nobody is waiting */
320
 
        if(DEBUG)fprintf(stderr,"SUNLOCK=%d node=%d list=(%d,%d)\n",
321
 
                          armci_me, i, blocked[i].mutex, blocked[i].turn);
322
 
        if((blocked[i].mutex == mutex) && (blocked[i].turn == Ticket)){
323
 
           p = i;
324
 
           break;
325
 
        }
326
 
     }
327
 
 
328
 
     /* send Ticket to a process waiting for mutex */
329
 
     if(p != NOBODY){
330
 
        if(p == armci_me)armci_die("server_unlock: cannot unlock self",0);
331
 
        else {
332
 
 
333
 
          if(DEBUG)fprintf(stderr,"SUNLOCK=%d node=%d unlock ticket=%d go=%d\n",
334
 
                                         armci_me, proc, Ticket, p);
335
 
 
336
 
          /*   GA_SEND_REPLY(blocked[p].tag, &Ticket, sizeof(int), p); */
337
 
          *ptag = blocked[p].tag;
338
 
          return p;
339
 
 
340
 
        }
341
 
     }
342
 
 
343
 
     return -1; /* nobody is waiting */
344
 
}
345
 
 
346
 
 
347
 
 
348
 
void PARMCI_Lock(int mutex, int proc)        
349
 
{
350
 
#if defined(SERVER_LOCK)
351
 
int direct;
352
 
#endif
353
 
 
354
 
        if(DEBUG)fprintf(stderr,"%d enter lock\n",armci_me);
355
 
 
356
 
        if(!num_mutexes) armci_die("armci_lock: create mutexes first",0);
357
 
 
358
 
        if(mutex > glob_mutex[proc].count)
359
 
           armci_die2("armci_lock: mutex not allocated", mutex,
360
 
                      glob_mutex[proc].count); 
361
 
 
362
 
        if(armci_nproc == 1) return;
363
 
 
364
 
#       if defined(SERVER_LOCK)
365
 
           direct=SAMECLUSNODE(proc); 
366
 
           if(!direct) 
367
 
              armci_rem_lock(mutex,proc, glob_mutex[proc].tickets + mutex );
368
 
           else
369
 
#       endif
370
 
              armci_generic_lock(mutex,proc);
371
 
 
372
 
        if(DEBUG)fprintf(stderr,"%d leave lock\n",armci_me);
373
 
}
374
 
 
375
 
 
376
 
 
377
 
void PARMCI_Unlock(int mutex, int proc)
378
 
{
379
 
        if(DEBUG)fprintf(stderr,"%d enter unlock\n",armci_me);
380
 
 
381
 
        if(!num_mutexes) armci_die("armci_lock: create mutexes first",0);
382
 
 
383
 
        if(mutex > glob_mutex[proc].count)
384
 
           armci_die2("armci_lock: mutex not allocated", mutex,
385
 
                      glob_mutex[proc].count); 
386
 
 
387
 
        if(armci_nproc == 1) return;
388
 
 
389
 
#       if defined(SERVER_LOCK)
390
 
           if(armci_nclus >1) { 
391
 
             if(proc != armci_me)
392
 
               armci_rem_unlock(mutex, proc, glob_mutex[proc].tickets[mutex]);
393
 
             else {
394
 
               int ticket = glob_mutex[proc].tickets[mutex];
395
 
               msg_tag_t tag;
396
 
               int waiting;
397
 
               
398
 
               waiting = armci_server_unlock_mutex(mutex, proc, ticket, &tag);
399
 
               if(waiting >-1)
400
 
                 armci_unlock_waiting_process(tag, waiting, ++ticket);
401
 
             }
402
 
           }
403
 
           else
404
 
#       endif
405
 
             armci_generic_unlock(mutex, proc);
406
 
 
407
 
        if(DEBUG)fprintf(stderr,"%d leave unlock\n",armci_me);
408
 
}