HPCToolkit
cskiplist.c
Go to the documentation of this file.
1 // * BeginRiceCopyright *****************************************************
2 //
3 // $HeadURL$
4 // $Id$
5 //
6 // --------------------------------------------------------------------------
7 // Part of HPCToolkit (hpctoolkit.org)
8 //
9 // Information about sources of support for research and development of
10 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
11 // --------------------------------------------------------------------------
12 //
13 // Copyright ((c)) 2002-2019, Rice University
14 // All rights reserved.
15 //
16 // Redistribution and use in source and binary forms, with or without
17 // modification, are permitted provided that the following conditions are
18 // met:
19 //
20 // * Redistributions of source code must retain the above copyright
21 // notice, this list of conditions and the following disclaimer.
22 //
23 // * Redistributions in binary form must reproduce the above copyright
24 // notice, this list of conditions and the following disclaimer in the
25 // documentation and/or other materials provided with the distribution.
26 //
27 // * Neither the name of Rice University (RICE) nor the names of its
28 // contributors may be used to endorse or promote products derived from
29 // this software without specific prior written permission.
30 //
31 // This software is provided by RICE and contributors "as is" and any
32 // express or implied warranties, including, but not limited to, the
33 // implied warranties of merchantability and fitness for a particular
34 // purpose are disclaimed. In no event shall RICE or contributors be
35 // liable for any direct, indirect, incidental, special, exemplary, or
36 // consequential damages (including, but not limited to, procurement of
37 // substitute goods or services; loss of use, data, or profits; or
38 // business interruption) however caused and on any theory of liability,
39 // whether in contract, strict liability, or tort (including negligence
40 // or otherwise) arising in any way out of the use of this software, even
41 // if advised of the possibility of such damage.
42 //
43 // ******************************************************* EndRiceCopyright *
44 
45 
46 
47 //******************************************************************************
48 //
49 // File: cskiplist_abstract.c
50 // $HeadURL$
51 //
52 // Purpose:
53 // Implement the API for a concurrent skip list as specified in
54 // cskiplist_abstract.h
55 //
56 //******************************************************************************
57 
58 //******************************************************************************
59 // global includes
60 //******************************************************************************
61 
62 
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <string.h>
66 #include <assert.h>
67 
68 #include "randomizer.h"
69 #include "cskiplist.h"
70 
71 //******************************************************************************
72 // macros
73 //******************************************************************************
74 
75 #ifndef NULL
76 #define NULL 0
77 #endif
78 
79 #define CSKL_DEBUG 0
80 
81 #define NO_LAYER -1
82 
83 // number of bytes in a skip list node with L levels
84 #define SIZEOF_CSKLNODE_T(L) (sizeof(csklnode_t) + sizeof(void*) * L)
85 
86 #define NUM_NODES 10
87 
88 
89 //******************************************************************************
90 // implementation types
91 //******************************************************************************
92 
93 #if OPAQUE_TYPE
94 // opaque type not supported by gcc 4.4.*
95 #include "cskiplist_defs.h"
96 #endif
97 
98 
99 typedef enum {
103 
104 
105 static csklnode_t *GF_cskl_nodes = NULL; // global free csklnode list
106 static mcs_lock_t GFCN_lock; // lock for GF_cskl_nodes
107 static __thread csklnode_t *_lf_cskl_nodes = NULL; // thread local free csklnode list
108 
109 
110 //******************************************************************************
111 // private operations
112 //******************************************************************************
113 
114 /*
115  * allocate a node of a specified height.
116  */
117 static csklnode_t *
118 csklnode_alloc_node(int height, mem_alloc m_alloc)
119 {
120  csklnode_t* node = (csklnode_t*)m_alloc(SIZEOF_CSKLNODE_T(height));
121  node->height = height;
122  node->fully_linked = false;
123  node->marked = false;
124  mcs_init(&(node->lock));
125  return node;
126 }
127 
128 /*
129  * add a bunch of nodes to _lf_cskl_nodes
130  */
131 static void
133  int maxheight,
134  mem_alloc m_alloc)
135 {
136  for (int i = 0; i < NUM_NODES; i++) {
137  int my_height = random_level(maxheight);
138  csklnode_t* node = csklnode_alloc_node(my_height, m_alloc);
139  node->nexts[0] = _lf_cskl_nodes;
141  }
142 }
143 
144 
145 /*
146  * remove and return the head of _lf_cskl_nodes
147  * pre-condtion: _lf_cskl_nodes != NULL
148  */
149 static csklnode_t*
151  void* val)
152 {
153  csklnode_t *ans = _lf_cskl_nodes;
155  ans->nexts[0] = NULL;
156  ans->val = val;
157  return ans;
158 }
159 
160 /*
161  * return node to lfl
162  */
163 static void
165 {
166  node->nexts[0] = _lf_cskl_nodes;
168 }
169 
170 
171 /*
172  * trylock GF_cskl_nodes;
173  * if GF_cskl_nodes != NULL, transfer a bunch of nodes to _lf_cskl_nodes,
174  * otherwise add a few nodes to _lf_cskl_nodes.
175  */
176 static void
178  int maxheight,
179  mem_alloc m_alloc)
180 {
181  mcs_node_t me;
182  bool acquired = mcs_trylock(&GFCN_lock, &me);
183  if (acquired) {
184  if (GF_cskl_nodes) {
185  // transfer a bunch of nodes the global free list to the local free list
186  int n = 0;
187  while (GF_cskl_nodes && n < NUM_NODES) {
188  csklnode_t *head = GF_cskl_nodes;
189  GF_cskl_nodes = GF_cskl_nodes->nexts[0];
190  head->nexts[0] = _lf_cskl_nodes;
191  _lf_cskl_nodes = head;
192  n++;
193  }
194  }
195  mcs_unlock(&GFCN_lock, &me);
196  }
197  if (!_lf_cskl_nodes) {
198  csklnode_add_nodes_to_lfl(maxheight, m_alloc);
199  }
200 }
201 
202 static csklnode_t*
204  void* val,
205  int maxheight,
206  mem_alloc m_alloc)
207 {
208  if (!_lf_cskl_nodes) {
209  csklnode_populate_lfl(maxheight, m_alloc);
210  }
211 
212 #if CSKL_DEBUG
213  assert(_lf_cskl_nodes);
214 #endif
215 
216  return csklnode_alloc_from_lfl(val);
217 }
218 
219 static inline bool
221 {
222  return (candidate->fully_linked &&
223  candidate->height - 1 == layer &&
224  !candidate->marked);
225 }
226 
244 static int
246 (val_cmp compare, // comparator used for searching
247  int max_height, // number of list levels
248  csklnode_t *pred, // full node < val
249  void* val, // the value we are seeking
250  csklnode_t *preds[], // return value: nodes < val
251  csklnode_t *succs[], // return value: nodes >= val
252  cskiplist_find_type ft) // is info needed at all layers?
253 {
254  int found_layer = NO_LAYER;
255  for (int layer = max_height-1; layer >= 0; layer--) {
256  csklnode_t *current = pred->nexts[layer];
257 
258  // look along a layer until we find a value that is not to the left
259  // of our value of interest
260  while (compare(current->val, val) < 0) { // i.e. current->val < val
261  pred = current; // invariant pred->val < val is maintained
262  current = pred->nexts[layer];
263  }
264  // loop exit condition: val <= curr->val
265  // loop invariant: pred->val < val
266 
267  // remember the 'layer' node < val:
268  preds[layer] = pred; // preds[layer]->val < val, by the loop invariant
269  // remember the 'layer' node >= val:
270  succs[layer] = current; // val <= succs[layer]->val, by the loop exit condition
271 
272  if (found_layer == NO_LAYER && // if we haven't already found a match
273  compare(current->val, val) == 0) { // and the current val is a match
274  found_layer = layer; // remember the layer where we matched
275  // found_layer is the first layer from the top where val is found.
276  // some clients of find don't need results for layers below found_layer
277  if (ft == cskiplist_find_early_exit)
278  break;
279  }
280  }
281 
282  return found_layer;
283 }
284 
285 static csklnode_t *
286 cskiplist_find(val_cmp compare, cskiplist_t *cskl, void* value)
287 {
288  // Acquire lock before reading:
289  pfq_rwlock_read_lock(&cskl->lock);
290 
291  int max_height = cskl->max_height;
292  csklnode_t *preds[max_height];
293  csklnode_t *succs[max_height];
294  int layer = cskiplist_find_helper(compare, max_height, cskl->left_sentinel, value, preds,
296  csklnode_t *node = NULL;
297  if (layer != NO_LAYER) {
298  node = succs[layer];
299  if (!node->fully_linked || node->marked)
300  node = NULL;
301  }
302 
303  // Release lock after reading:
305 
306  return node;
307 }
308 
309 static void inline
311 (csklnode_t *preds[],
312  mcs_node_t mcs_nodes[],
313  int highestLocked)
314 {
315  // unlock each of my predecessors, as necessary
316  csklnode_t *prevPred = NULL;
317  for (int layer = 0; layer <= highestLocked; layer++) {
318  csklnode_t *pred = preds[layer];
319  if (pred != prevPred) {
320  mcs_unlock(&pred->lock, &mcs_nodes[layer]);
321  }
322  prevPred = pred;
323  }
324 }
325 
326 static void
327 cskl_links_tostr(int max_height, char str[], int max_cskl_str_len)
328 {
329  int str_len;
330  str[0] = '\0';
331  for (int i = 0; i < max_height; i++) {
332  str_len = strlen(str);
333  strncat(str, " |", max_cskl_str_len - str_len - 1);
334  }
335  str_len = strlen(str);
336  strncat(str, "\n", max_cskl_str_len - str_len - 1);
337 }
338 
339 static bool
340 cskl_del_bulk_unsynch(val_cmp cmpfn, cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
341 {
342  int max_height = cskl->max_height;
343 
344  csklnode_t* lpreds[max_height];
345  csklnode_t* other[max_height];
346  csklnode_t* hsuccs[max_height];
347  csklnode_t** succs;
348 
349  // Acquire lock before writing:
351  pfq_rwlock_write_lock(&cskl->lock, &me);
352 
353  //----------------------------------------------------------------------------
354  // Look for a node matching low
355  //----------------------------------------------------------------------------
356  int hlayer = cskiplist_find_helper(cmpfn, max_height, cskl->left_sentinel, lo, lpreds,
357  other, cskiplist_find_full);
358  csklnode_t *first = lpreds[0]->nexts[0];
359  if (lo == hi)
360  succs = lpreds;
361  else {
362  //----------------------------------------------------------------------------
363  // Look for a node matching high
364  //----------------------------------------------------------------------------
365  succs = &hsuccs[0];
366  hlayer = cskiplist_find_helper(cmpfn, max_height, lpreds[max_height-1],
367  hi, succs, other, cskiplist_find_full);
368 
369  //
370  //----------------------------------------------------------------------------
371  // Complete the deletion: Splice out node at all layers from 0..max_height-1
372  //----------------------------------------------------------------------------
373  int layer = max_height - 1;
374  while (layer > hlayer) {
375  // Splice out nodes at layer.
376  lpreds[layer]->nexts[layer] = succs[layer]->nexts[layer];
377  layer--;
378  }
379  }
380 
381  while (hlayer >= 0) {
382  // Splice out nodes at layer, including found node.
383  lpreds[hlayer]->nexts[hlayer] = succs[hlayer]->nexts[hlayer]->nexts[hlayer];
384  hlayer--;
385  }
386  csklnode_t *last = lpreds[0]->nexts[0];
387 
388  //----------------------------------------------------------------------------
389  // Delete all of the nodes between first and last.
390  //----------------------------------------------------------------------------
391 
392  for (csklnode_t *node = first; node != last;) {
393  csklnode_t *next = node->nexts[0]; // remember the pointer before trashing node
394  m_free(node); // delete node
395  node = next;
396  }
397 
398  // Release lock after writing:
399  pfq_rwlock_write_unlock(&cskl->lock, &me);
400 
401  return first != last;
402 }
403 
404 //******************************************************************************
405 // interface operations
406 //******************************************************************************
407 
408 void
410 {
411 #if CSKL_DEBUG
412  printf("DXN_DBG: cskl_init mcs_init(&GFCN_lock)\n");
413 #endif
414  mcs_init(&GFCN_lock);
415 }
416 
417 /*
418  * only free non null csklnode_t*
419  * pre-condition: anode is of type csklnpde_t*
420  */
421 void
422 cskl_free(void* anode)
423 {
424  if (!anode) return;
425  // add node to the front of the global free csklnode list.
426  mcs_node_t me;
427  csklnode_t *node = (csklnode_t*)anode;
428  for (int i = 0; i < node->height; i++) {
429  node->nexts[i] = NULL;
430  }
431  node->fully_linked = false;
432  node->marked = false;
433  mcs_lock(&GFCN_lock, &me);
434  node->nexts[0] = GF_cskl_nodes;
435  GF_cskl_nodes = node;
436  mcs_unlock(&GFCN_lock, &me);
437 }
438 
439 
442  void* lsentinel,
443  void* rsentinel,
444  int max_height,
445  val_cmp compare,
446  val_cmp inrange,
447  mem_alloc m_alloc)
448 {
449  cskiplist_t* cskl = (cskiplist_t*)m_alloc(sizeof(cskiplist_t));
450  cskl->max_height = max_height;
451  cskl->compare = compare;
452  cskl->inrange = inrange;
453  pfq_rwlock_init(&cskl->lock);
454 
455  // create sentinel nodes
456  csklnode_t *left = cskl->left_sentinel = csklnode_alloc_node(max_height, m_alloc);
457  csklnode_t *right = cskl->right_sentinel = csklnode_alloc_node(0, m_alloc);
458  left->val = lsentinel;
459  right->val = rsentinel;
460  // hook sentinel nodes in empty list
461  for(int i = 0; i < max_height; i++)
462  left->nexts[i] = right;
463 
464  return cskl;
465 }
466 
467 void*
468 cskl_cmp_find(cskiplist_t *cskl, void *value)
469 {
470  csklnode_t *found = cskiplist_find(cskl->compare, cskl, value);
471  return found? found->val: NULL; // found->val == value
472 }
473 
474 void*
475 cskl_inrange_find(cskiplist_t *cskl, void *value)
476 {
477  csklnode_t *found = cskiplist_find(cskl->inrange, cskl, value);
478  return found? found->val: NULL; // found->val contains value
479 }
480 
481 
482 csklnode_t *
483 cskl_insert(cskiplist_t *cskl, void *value,
484  mem_alloc m_alloc)
485 {
486  int max_height = cskl->max_height;
487  csklnode_t *preds[max_height];
488  csklnode_t *succs[max_height];
489  csklnode_t *node;
490 
491  // allocate my node
492  csklnode_t *new_node = csklnode_malloc(value, max_height, m_alloc);
493 
494  for (node = NULL; node == NULL; pfq_rwlock_read_unlock(&cskl->lock)) {
495  // Acquire lock before reading:
496  pfq_rwlock_read_lock(&cskl->lock);
497 
498  int found_layer= cskiplist_find_helper(cskl->compare,
499  max_height, cskl->left_sentinel, value, preds, succs,
501 
502  if (found_layer != NO_LAYER) {
503  node = succs[found_layer];
504  if (!node->marked) {
505  csklnode_free_to_lfl(new_node);
506  while (!node->fully_linked);
507  } else
508  // node is marked for deletion by some other thread, so this thread needs
509  // to try to insert again by going to the end of this for(;;) loop. As
510  // this thread tries to insert again, there may be another the thread
511  // that succeeds in inserting value before this thread gets a chance to.
512  node = NULL;
513  continue;
514  }
515 
516 
517  //--------------------------------------------------------------------------
518  // Acquire a lock on node's predecessor at each layer.
519  //
520  // valid condition:
521  // no predecessor is marked
522  // no successor is marked
523  // each of my predecessors still points to the successor I recorded
524  //
525  // If the valid condition is not satisfied, unlock all of my predecessors
526  // and retry.
527  //--------------------------------------------------------------------------
528  int my_height = new_node->height;
529  mcs_node_t mcs_nodes[my_height];
530  int highestLocked = -1;
531  int layer;
532  csklnode_t *prevPred = NULL;
533  for (layer = 0; layer < my_height; layer++) {
534  csklnode_t *pred = preds[layer];
535  csklnode_t *succ = succs[layer];
536  if (pred != prevPred) {
537  mcs_lock(&pred->lock, &mcs_nodes[layer]);
538  highestLocked = layer;
539  prevPred = pred;
540  }
541  if (pred->marked || succ->marked || pred->nexts[layer] != succ)
542  break;
543  // my value better be less than the node I am inserting before
544  assert(cskl->compare(value, pred->nexts[layer]->val) == -1);
545  }
546  if (layer == my_height) {
547  // link new node in at levels [0 .. my_height-1]
548  node = new_node;
549  for (int layer = 0; layer < my_height; layer++) {
550  node->nexts[layer] = succs[layer];
551  preds[layer]->nexts[layer] = node;
552  }
553 
554  // mark the node as usable
555  node->fully_linked = true;
556  }
557 
558  // unlock each of my predecessors, as necessary
559  unlock_preds(preds, mcs_nodes, highestLocked);
560  }
561 
562  return node;
563 }
564 
565 /*
566  * TODO: this function is not used anywhere and leaks memory.
567  */
568 bool
569 cskl_delete(cskiplist_t *cskl, void *value)
570 {
571  int max_height = cskl->max_height;
572  bool node_is_marked = false;
573  csklnode_t *node = NULL;
574 
575  for (;;) {
576  csklnode_t *preds[max_height], *succs[max_height];
577  int height = -1;
578 
579  //--------------------------------------------------------------------------
580  // Look for a node matching v
581  //--------------------------------------------------------------------------
582  int layer = cskiplist_find_helper(cskl->compare, max_height, cskl->left_sentinel, value,
583  preds, succs, cskiplist_find_full);
584 
585  //--------------------------------------------------------------------------
586  // A matching node is available to remove. We may have marked it earlier as
587  // we began its removal.
588  //--------------------------------------------------------------------------
589  if (node_is_marked ||
590  (layer != NO_LAYER &&
591  cskiplist_node_is_removable(succs[layer], layer))) {
592 
593  //------------------------------------------------------------------------
594  // if I haven't already marked this node for deletion, do so.
595  //------------------------------------------------------------------------
596  mcs_node_t mcs_nodes[layer + 1];
597  if (!node_is_marked) {
598  node = succs[layer];
599  height = node->height;
600  mcs_lock(&node->lock, &mcs_nodes[layer]);
601  if (node->marked) {
602  mcs_unlock(&node->lock, &mcs_nodes[layer]);
603  return false;
604  }
605  node->marked = true;
606  node_is_marked = true;
607  }
608  //------------------------------------------------------------------------
609  // Post-condition: Node is marked and locked.
610  //------------------------------------------------------------------------
611 
612  //------------------------------------------------------------------------
613  // Acquire a lock on node's predecessor at each layer.
614  //
615  // valid condition:
616  // no predecessor is marked
617  // each of my predecessors still points to the successor I recorded (me)
618  //
619  // If the valid condition is not satisfied, unlock all of my predecessors
620  // and retry.
621  //------------------------------------------------------------------------
622  int highestLocked = -1;
623  csklnode_t *pred, *succ;
624  csklnode_t *prevPred = NULL;
625  bool valid = true;
626  for (int layer = 0; valid && (layer < height); layer++) {
627  pred = preds[layer];
628  succ = succs[layer];
629  if (pred != prevPred) {
630  mcs_lock(&pred->lock, &mcs_nodes[layer]);
631  highestLocked = layer;
632  prevPred = pred;
633  }
634  valid = !pred->marked && pred->nexts[layer] == succ;
635  }
636 
637  if (!valid) {
638  unlock_preds(preds, mcs_nodes, highestLocked);
639  continue;
640  }
641  //-----------------------------------------------------------------------
642  // Post-condition: All predecessors are locked for delete.
643  //-----------------------------------------------------------------------
644 
645  //-----------------------------------------------------------------------
646  // Complete the deletion: Splice out node at each layer and release lock
647  // on node's predecessor at each layer.
648  //-----------------------------------------------------------------------
649  for (int layer = height - 1; layer >= 0; layer--) {
650  // Splice out node at layer.
651  preds[layer]->nexts[layer] = node->nexts[layer];
652  }
653 
654  // Unlock self.
655  mcs_unlock(&node->lock, &mcs_nodes[layer]);
656 
657  unlock_preds(preds, mcs_nodes, highestLocked);
658  return true;
659  } else {
660  return false;
661  }
662  }
663 }
664 
665 bool
666 cskl_cmp_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
667 {
668  return cskl_del_bulk_unsynch(cskl->compare, cskl, lo, hi, m_free);
669 }
670 
671 bool
672 cskl_inrange_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
673 {
674  return cskl_del_bulk_unsynch(cskl->inrange, cskl, lo, hi, m_free);
675 }
676 
677 
678 void cskl_levels_tostr (int height, int max_height, char str[],
679  int max_cskl_str_len)
680 {
681  int str_len;
682  str[0] = '\0';
683  strcat(str, " +");
684  for (int i = 1; i < height; i++) {
685  str_len = strlen(str);
686  strncat(str, "-+", max_cskl_str_len - str_len - 1);
687  }
688  for (int i = height; i < max_height; i++) {
689  str_len = strlen(str);
690  strncat(str, " |", max_cskl_str_len - str_len - 1);
691  }
692  str_len = strlen(str);
693  strncat(str, " ", max_cskl_str_len - str_len - 1);
694 }
695 
696 void
697 cskl_append_node_str(char nodestr[], char str[], int max_cskl_str_len)
698 {
699  int str_len = strlen(str);
700  strncat(str, nodestr, max_cskl_str_len - str_len - 1);
701  str_len = strlen(str);
702  strncat(str, "\n", max_cskl_str_len - str_len - 1);
703 }
704 
705 void
706 cskl_tostr(cskiplist_t *cskl, cskl_node_tostr node_tostr, char csklstr[], int max_cskl_str_len)
707 {
708  // Acquire lock before reading the cskiplist to build its string representation:
709  pfq_rwlock_read_lock(&cskl->lock);
710 
711  int max_height = cskl->max_height;
712  csklnode_t *node = cskl->left_sentinel;
714 
715  int temp_len = max_cskl_str_len/2;
716  char temp_buff[temp_len];
717  int str_len = 0;
718 
719  for (; ; node = node->nexts[0]) {
720  cskl_links_tostr(max_height, temp_buff, temp_len - 1);
721  strncat(csklstr, temp_buff, max_cskl_str_len - str_len - 1);
722  str_len = strlen(csklstr);
723  cskl_levels_tostr(node->height, max_height, csklstr + str_len, max_cskl_str_len - str_len - 1);
724  str_len = strlen(csklstr);
725  node_tostr(node->val, node->height, max_height, temp_buff, temp_len - 1); // abstract function
726  strncat(csklstr, temp_buff, max_cskl_str_len - str_len - 1);
727  str_len = strlen(csklstr);
728  if (node == right) break;
729  }
730  strncat(csklstr, "\n", max_cskl_str_len - str_len - 1);
731 
732  // Release lock after building the string representation:
734 
735 }
736 
737 static void
738 cskl_links_dump(csklnode_t *node, int max_height)
739 {
740  int i;
741  int height = node->height;
742 
743  printf("0x%016lx: ", (unsigned long) node);
744 
745  // links [0..height)
746  for (i = 0; i < height; i++) {
747  printf("0x%016lx ", (unsigned long) node->nexts[i]);
748  }
749 
750  // links not present [height..max_height)
751  for (i = height; i < max_height; i++) {
752  printf("------------------ ");
753  }
754 }
755 
756 
757 #define NODE_STR_LEN 4096
758 
759 void
761 {
762  pfq_rwlock_read_lock(&cskl->lock);
763 
764  int max_height = cskl->max_height;
765  csklnode_t *node = cskl->left_sentinel;
767 
768  char nodestr[NODE_STR_LEN];
769 
770  for (; ; node = node->nexts[0]) {
771  cskl_links_dump(node, max_height);
772  node_tostr(node->val, node->height, max_height, nodestr, NODE_STR_LEN -1);
773  printf("%s", nodestr);
774  if (node == right) break;
775  }
776  printf("\n");
777 
779 }
780 
781 
782 static void
784 {
785  int i;
786  int height = node->height;
787 
788  printf("0x%016lx: ", (unsigned long) node);
789 
790  printf(" +");
791  // links [1..height)
792  for (i = 1; i < height; i++) {
793  printf("-+");
794  }
795 
796  // links not present [height..max_height)
797  for (i = height; i < max_height; i++) {
798  printf(" |");
799  }
800 }
801 
802 
803 void
805 {
806  pfq_rwlock_read_lock(&cskl->lock);
807 
808  int max_height = cskl->max_height;
809  csklnode_t *node;
810 
811  for (node = cskl->left_sentinel; node; node = node->nexts[0]) {
812  cskl_links_print(node, max_height);
813 
814  char nodestr[NODE_STR_LEN];
815  node_tostr(node->val, node->height, max_height, nodestr, NODE_STR_LEN -1);
816  printf("%s", nodestr);
817  }
818  printf("\n");
819 
821 }
822 
823 
824 int
826 (
827  val_cmp compare, // compare node values
828  int max_height, // number of list levels
829  cskl_node_tostr node_tostr, // print node value
831 )
832 {
833  int i;
834  int correct = 1;
835  int succIsGreater[node->height];
836  for (i = 0; i < node->height; i++) {
837  csklnode_t *succ = node->nexts[i];
838  succIsGreater[i] = (compare(node->val, succ->val) == -1);
839  correct &= succIsGreater[i];
840  }
841  if (!correct) {
842  for (i = 0; i < node->height; i++) {
843  printf("%c", succIsGreater[i] ? '+' : 'X');
844  }
845  for (i = node->height; i < max_height; i++) {
846  printf("-");
847  }
848  printf(" ");
849 
850  char nodestr[NODE_STR_LEN];
851  cskl_links_dump(node, max_height);
852  node_tostr(node->val, node->height, max_height, nodestr, NODE_STR_LEN -1);
853  printf("%s", nodestr);
854  }
855  return correct;
856 }
857 
858 
859 void
861 (
862  cskiplist_t *cs, // cskiplist instance
863  cskl_node_tostr node_tostr // print node value
864  )
865 {
866  int max_height = cs->max_height;
867  csklnode_t *node = cs->left_sentinel;
868 
869  bool correct = true;
870  printf("***** BEGIN CHECK: skip list %p\n", cs);
871  for (node = cs->left_sentinel; node != cs->right_sentinel; node = node->nexts[0]) {
872  correct &= cskl_check_node_dump(cs->compare, max_height, node_tostr, node);
873  }
874  printf("***** END CHECK: skip list %p is %s\n", cs, correct ? "correct" : "incorrect");
875 }
876 
static void cskl_links_tostr(int max_height, char str[], int max_cskl_str_len)
Definition: cskiplist.c:327
void *(* mem_alloc)(size_t size)
Definition: mem_manager.h:17
volatile bool marked
val_cmp compare
void mcs_lock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:77
static void csklnode_free_to_lfl(csklnode_t *node)
Definition: cskiplist.c:164
#define NUM_NODES
Definition: cskiplist.c:86
static mcs_lock_t GFCN_lock
Definition: cskiplist.c:106
void cskl_tostr(cskiplist_t *cskl, cskl_node_tostr node_tostr, char csklstr[], int max_cskl_str_len)
Definition: cskiplist.c:706
void(* cskl_node_tostr)(void *node_val, int node_height, int max_height, char str[], int max_cskl_str_len)
Definition: cskiplist.h:96
static void cskl_links_print(csklnode_t *node, int max_height)
Definition: cskiplist.c:783
cskiplist_t * cskl_new(void *lsentinel, void *rsentinel, int max_height, val_cmp compare, val_cmp inrange, mem_alloc m_alloc)
Definition: cskiplist.c:441
struct csklnode_s * nexts[]
static bool cskiplist_node_is_removable(csklnode_t *candidate, int layer)
Definition: cskiplist.c:220
void cskl_free(void *anode)
Definition: cskiplist.c:422
bool cskl_delete(cskiplist_t *cskl, void *value)
Definition: cskiplist.c:569
volatile bool fully_linked
bool cskl_inrange_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
Definition: cskiplist.c:672
pfq_rwlock_t lock
void cskl_print(cskiplist_t *cskl, cskl_node_tostr node_tostr)
Definition: cskiplist.c:804
int random_level(int max_height)
Definition: randomizer.c:23
void * cskl_inrange_find(cskiplist_t *cskl, void *value)
Definition: cskiplist.c:475
cct_node_t * node
Definition: cct.c:128
static int cskiplist_find_helper(val_cmp compare, int max_height, csklnode_t *pred, void *val, csklnode_t *preds[], csklnode_t *succs[], cskiplist_find_type ft)
Definition: cskiplist.c:246
#define NO_LAYER
Definition: cskiplist.c:81
char val[]
Definition: binarytree.h:101
bool cskl_cmp_del_bulk_unsynch(cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
Definition: cskiplist.c:666
void pfq_rwlock_init(pfq_rwlock_t *l)
Definition: pfq-rwlock.c:110
struct binarytree_s * right
Definition: binarytree.h:100
int compare(SrcFile::ln x, SrcFile::ln y)
Definition: SrcFile.hpp:80
bool mcs_trylock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:122
static void cskl_links_dump(csklnode_t *node, int max_height)
Definition: cskiplist.c:738
void mcs_unlock(mcs_lock_t *l, mcs_node_t *me)
Definition: mcs-lock.c:146
static csklnode_t * GF_cskl_nodes
Definition: cskiplist.c:105
void pfq_rwlock_write_lock(pfq_rwlock_t *l, pfq_rwlock_node_t *me)
Definition: pfq-rwlock.c:149
static __thread csklnode_t * _lf_cskl_nodes
Definition: cskiplist.c:107
static csklnode_t * csklnode_malloc(void *val, int maxheight, mem_alloc m_alloc)
Definition: cskiplist.c:203
void cskl_check_dump(cskiplist_t *cs, cskl_node_tostr node_tostr)
Definition: cskiplist.c:861
val_cmp inrange
#define SIZEOF_CSKLNODE_T(L)
Definition: cskiplist.c:84
void pfq_rwlock_read_lock(pfq_rwlock_t *l)
Definition: pfq-rwlock.c:122
static void unlock_preds(csklnode_t *preds[], mcs_node_t mcs_nodes[], int highestLocked)
Definition: cskiplist.c:311
int cskl_check_node_dump(val_cmp compare, int max_height, cskl_node_tostr node_tostr, csklnode_t *node)
Definition: cskiplist.c:826
#define NODE_STR_LEN
Definition: cskiplist.c:757
static void csklnode_populate_lfl(int maxheight, mem_alloc m_alloc)
Definition: cskiplist.c:177
void * cskl_cmp_find(cskiplist_t *cskl, void *value)
Definition: cskiplist.c:468
void pfq_rwlock_write_unlock(pfq_rwlock_t *l, pfq_rwlock_node_t *me)
Definition: pfq-rwlock.c:211
int(* val_cmp)(void *lhs, void *rhs)
Definition: generic_val.h:32
void pfq_rwlock_read_unlock(pfq_rwlock_t *l)
Definition: pfq-rwlock.c:134
void cskl_init()
Definition: cskiplist.c:409
static void csklnode_add_nodes_to_lfl(int maxheight, mem_alloc m_alloc)
Definition: cskiplist.c:132
csklnode_t * cskl_insert(cskiplist_t *cskl, void *value, mem_alloc m_alloc)
Definition: cskiplist.c:483
void cskl_append_node_str(char nodestr[], char str[], int max_cskl_str_len)
Definition: cskiplist.c:697
struct binarytree_s * left
Definition: binarytree.h:99
static csklnode_t * cskiplist_find(val_cmp compare, cskiplist_t *cskl, void *value)
Definition: cskiplist.c:286
bool found
Definition: cct.c:129
csklnode_t * right_sentinel
#define NULL
Definition: cskiplist.c:76
static csklnode_t * csklnode_alloc_from_lfl(void *val)
Definition: cskiplist.c:150
void cskl_levels_tostr(int height, int max_height, char str[], int max_cskl_str_len)
Definition: cskiplist.c:678
cskiplist_find_type
Definition: cskiplist.c:99
static csklnode_t * csklnode_alloc_node(int height, mem_alloc m_alloc)
Definition: cskiplist.c:118
void cskl_dump(cskiplist_t *cskl, cskl_node_tostr node_tostr)
Definition: cskiplist.c:760
mcs_lock_t lock
static bool cskl_del_bulk_unsynch(val_cmp cmpfn, cskiplist_t *cskl, void *lo, void *hi, mem_free m_free)
Definition: cskiplist.c:340
<!-- ********************************************************************--> n<!-- HPCToolkit Experiment DTD --> n<!-- Version 2.1 --> n<!-- ********************************************************************--> n<!ELEMENT HPCToolkitExperiment(Header,(SecCallPathProfile|SecFlatProfile) *)> n<!ATTLIST HPCToolkitExperiment\n version CDATA #REQUIRED > n n<!-- ******************************************************************--> n n<!-- Info/NV:flexible name-value pairs:(n) ame;(t) ype;(v) alue --> n<!ELEMENT Info(NV *)> n<!ATTLIST Info\n n CDATA #IMPLIED > n<!ELEMENT NV EMPTY > n<!ATTLIST NV\n n CDATA #REQUIRED\n t CDATA #IMPLIED\n v CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Header --> n<!-- ******************************************************************--> n<!ELEMENT Header(Info *)> n<!ATTLIST Header\n n CDATA #REQUIRED > n n<!-- ******************************************************************--> n<!-- Section Header --> n<!-- ******************************************************************--> n<!ELEMENT SecHeader(MetricTable?, MetricDBTable?, TraceDBTable?, LoadModuleTable?, FileTable?, ProcedureTable?, Info *)> n n<!-- MetricTable:--> n<!ELEMENT MetricTable(Metric) * > n n<!-- Metric:(i) d;(n) ame --> n<!--(v) alue-type:transient type of values --> n<!--(t) ype:persistent type of metric --> n<!-- fmt:format;show;--> n<!ELEMENT Metric(MetricFormula *, Info?)> n<!ATTLIST Metric\n i CDATA #REQUIRED\n n CDATA #REQUIRED\n es CDATA #IMPLIED\n em CDATA #IMPLIED\n ep CDATA #IMPLIED\n v(raw|final|derived-incr|derived) \"raw\\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ fmt CDATA #IMPLIED\ show (1|0) \1\\ show-percent (1|0) \1> n n<!-- MetricFormula represents derived metrics: (t)ype; (frm): formula --> n<!ELEMENT MetricFormula (Info?)> n<!ATTLIST MetricFormula\ t (combine|finalize) \finalize\\ i CDATA #IMPLIED\ frm CDATA #REQUIRED> n n<!-- Metric data, used in sections: (n)ame [from Metric]; (v)alue --> n<!ELEMENT M EMPTY> n<!ATTLIST M\ n CDATA #REQUIRED\ v CDATA #REQUIRED> n n<!-- MetricDBTable: --> n<!ELEMENT MetricDBTable (MetricDB)*> n n<!-- MetricDB: (i)d; (n)ame --> n<!-- (t)ype: persistent type of metric --> n<!-- db-glob: file glob describing files in metric db --> n<!-- db-id: id within metric db --> n<!-- db-num-metrics: number of metrics in db --> n<!-- db-header-sz: size (in bytes) of a db file header --> n<!ELEMENT MetricDB EMPTY> n<!ATTLIST MetricDB\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ t (inclusive|exclusive|nil) \nil\\ partner CDATA #IMPLIED\ db-glob CDATA #IMPLIED\ db-id CDATA #IMPLIED\ db-num-metrics CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- TraceDBTable: --> n<!ELEMENT TraceDBTable (TraceDB)> n n<!-- TraceDB: (i)d --> n<!-- db-min-time: min beginning time stamp (global) --> n<!-- db-max-time: max ending time stamp (global) --> n<!ELEMENT TraceDB EMPTY> n<!ATTLIST TraceDB\ i CDATA #REQUIRED\ db-glob CDATA #IMPLIED\ db-min-time CDATA #IMPLIED\ db-max-time CDATA #IMPLIED\ db-header-sz CDATA #IMPLIED> n n<!-- LoadModuleTable assigns a short name to a load module --> n<!ELEMENT LoadModuleTable (LoadModule)*> n n<!ELEMENT LoadModule (Info?)> n<!ATTLIST LoadModule\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- FileTable assigns a short name to a file --> n<!ELEMENT FileTable (File)*> n n<!ELEMENT File (Info?)> n<!ATTLIST File\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!-- ProcedureTable assigns a short name to a procedure --> n<!ELEMENT ProcedureTable (Procedure)*> n n<!-- Info/NV: flexible name-value pairs: (n)ame; (t)ype; (v)alue --> n<!-- f: family of the procedure (fake, root, ...)--> n<!ELEMENT Procedure (Info?)> n<!ATTLIST Procedure\ i CDATA #REQUIRED\ n CDATA #REQUIRED\ f CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Call path profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecCallPathProfile (SecHeader, SecCallPathProfileData)> n<!ATTLIST SecCallPathProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecCallPathProfileData (PF|M)*> n<!-- Procedure frame --> n<!-- (i)d: unique identifier for cross referencing --> n<!-- (s)tatic scope id --> n<!-- (n)ame: a string or an id in ProcedureTable --> n<!-- (lm) load module: a string or an id in LoadModuleTable --> n<!-- (f)ile name: a string or an id in LoadModuleTable --> n<!-- (l)ine range: \beg-end\ (inclusive range) --> n<!-- (a)lien: whether frame is alien to enclosing P --> n<!-- (str)uct: hpcstruct node id --> n<!-- (t)ype: hpcrun node type: memory access, variable declaration, ... --> n<!-- (v)ma-range-set: \{[beg-end), [beg-end)...}\ --> n<!ELEMENT PF (PF|Pr|L|C|S|M)*> n<!ATTLIST PF\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Procedure (static): GOAL: replace with 'P' --> n<!ELEMENT Pr (Pr|L|C|S|M)*> n<!ATTLIST Pr\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ n CDATA #REQUIRED\ lm CDATA #IMPLIED\ f CDATA #IMPLIED\ l CDATA #IMPLIED\ a (1|0) \0\\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Callsite (a special StatementRange) --> n<!ELEMENT C (PF|M)*> n<!ATTLIST C\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n n<!-- ****************************************************************** --> n<!-- Section: Flat profile --> n<!-- ****************************************************************** --> n<!ELEMENT SecFlatProfile (SecHeader, SecFlatProfileData)> n<!ATTLIST SecFlatProfile\ i CDATA #REQUIRED\ n CDATA #REQUIRED> n n<!ELEMENT SecFlatProfileData (LM|M)*> n<!-- Load module: (i)d; (n)ame; (v)ma-range-set --> n<!ELEMENT LM (F|P|M)*> n<!ATTLIST LM\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ v CDATA #IMPLIED> n<!-- File --> n<!ELEMENT F (P|L|S|M)*> n<!ATTLIST F\ i CDATA #IMPLIED\ n CDATA #REQUIRED> n<!-- Procedure (Note 1) --> n<!ELEMENT P (P|A|L|S|C|M)*> n<!ATTLIST P\ i CDATA #IMPLIED\ n CDATA #REQUIRED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Alien (Note 1) --> n<!ELEMENT A (A|L|S|C|M)*> n<!ATTLIST A\ i CDATA #IMPLIED\ f CDATA #IMPLIED\ n CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Loop (Note 1,2) --> n<!ELEMENT L (A|Pr|L|S|C|M)*> n<!ATTLIST L\ i CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ f CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Statement (Note 2) --> n<!-- (it): trace record identifier --> n<!ELEMENT S (S|M)*> n<!ATTLIST S\ i CDATA #IMPLIED\ it CDATA #IMPLIED\ s CDATA #IMPLIED\ l CDATA #IMPLIED\ str CDATA #IMPLIED\ v CDATA #IMPLIED> n<!-- Note 1: Contained Cs may not contain PFs --> n<!-- Note 2: The 's' attribute is not used for flat profiles --> n
csklnode_t * left_sentinel
static char * last
Definition: tokenize.c:65
void(* mem_free)(void *ptr)
Definition: mem_manager.h:18
static void mcs_init(mcs_lock_t *l)
Definition: mcs-lock.h:100