CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
List of all members | Public Member Functions | Private Member Functions | Private Attributes
RadixSort Class Reference

#include <IceRevisitedRadix.h>

Public Member Functions

udword GetNbHits () const
 Returns the number of eraly exits due to temporal coherence. More...
 
udword GetNbTotalCalls () const
 Returns the total number of calls to the radix sorter. More...
 
const udwordGetRanks () const
 Access to results. mRanks is a list of indices in sorted order,. More...
 
udwordGetRecyclable () const
 mIndices2 gets trashed on calling the sort routine, but More...
 
udword GetUsedRam () const
 
 RadixSort ()
 
udwordRelinquishRanks ()
 
RadixSortSort (const udword *input, udword nb, RadixHint hint=RADIX_SIGNED)
 
RadixSortSort (const float *input, udword nb)
 
 ~RadixSort ()
 

Private Member Functions

void CheckResize (udword nb)
 
bool Resize (udword nb)
 

Private Attributes

udword mCurrentSize
 Current size of the indices list. More...
 
udword mNbHits
 Number of early exits due to coherence. More...
 
udwordmRanks
 Two lists, swapped each pass. More...
 
udwordmRanks2
 
udword mTotalCalls
 Total number of calls to the sort routine. More...
 

Detailed Description

Revisited Radix Sort. This is my new radix routine:

History:

Author
Pierre Terdiman
Version
1.4
Date
August, 15, 1998

Definition at line 28 of file IceRevisitedRadix.h.

Constructor & Destructor Documentation

RadixSort::RadixSort ( )

Constructor.

Definition at line 188 of file IceRevisitedRadix.cc.

References INVALIDATE_RANKS.

Referenced by GetUsedRam().

188  : mCurrentSize(0), mRanks(nullptr), mRanks2(nullptr), mTotalCalls(0), mNbHits(0) {
189 #ifndef RADIX_LOCAL_RAM
190  // Allocate input-independent ram
191  mHistogram = new udword[256 * 4];
192  mLink = new udword[256];
193 #endif
194  // Initialize indices
196 }
#define INVALIDATE_RANKS
udword mTotalCalls
Total number of calls to the sort routine.
udword mCurrentSize
Current size of the indices list.
udword * mRanks2
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
udword * mRanks
Two lists, swapped each pass.
udword mNbHits
Number of early exits due to coherence.
RadixSort::~RadixSort ( )

Destructor.

Definition at line 203 of file IceRevisitedRadix.cc.

References DELETEARRAY, mRanks, and mRanks2.

203  {
204  // Release everything
205 #ifndef RADIX_LOCAL_RAM
206  DELETEARRAY(mLink);
207  DELETEARRAY(mHistogram);
208 #endif
211 }
udword * mRanks2
#define DELETEARRAY(x)
Deletes an array.
udword * mRanks
Two lists, swapped each pass.

Member Function Documentation

void RadixSort::CheckResize ( udword  nb)
inlineprivate

Definition at line 248 of file IceRevisitedRadix.cc.

References CURRENT_SIZE, INVALIDATE_RANKS, mCurrentSize, and Resize().

Referenced by Sort().

248  {
249  udword CurSize = CURRENT_SIZE;
250  if (nb != CurSize) {
251  if (nb > CurSize)
252  Resize(nb);
253  mCurrentSize = nb;
255  }
256 }
bool Resize(udword nb)
#define INVALIDATE_RANKS
udword mCurrentSize
Current size of the indices list.
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
#define CURRENT_SIZE
udword RadixSort::GetNbHits ( ) const
inline

Returns the number of eraly exits due to temporal coherence.

Definition at line 54 of file IceRevisitedRadix.h.

References mNbHits.

54 { return mNbHits; }
udword mNbHits
Number of early exits due to coherence.
udword RadixSort::GetNbTotalCalls ( ) const
inline

Returns the total number of calls to the radix sorter.

Definition at line 52 of file IceRevisitedRadix.h.

References mTotalCalls.

52 { return mTotalCalls; }
udword mTotalCalls
Total number of calls to the sort routine.
const udword* RadixSort::GetRanks ( ) const
inline

Access to results. mRanks is a list of indices in sorted order,.

Definition at line 39 of file IceRevisitedRadix.h.

References mRanks.

Referenced by mkfit::MkBuilder::import_seeds().

39 { return mRanks; }
udword * mRanks
Two lists, swapped each pass.
udword* RadixSort::GetRecyclable ( ) const
inline

mIndices2 gets trashed on calling the sort routine, but

Definition at line 47 of file IceRevisitedRadix.h.

References mRanks2.

47 { return mRanks2; }
udword * mRanks2
udword RadixSort::GetUsedRam ( ) const

Gets the ram used.

Returns
memory used in bytes

Definition at line 539 of file IceRevisitedRadix.cc.

References CURRENT_SIZE, and RadixSort().

539  {
540  udword UsedRam = sizeof(RadixSort);
541 #ifndef RADIX_LOCAL_RAM
542  UsedRam += 256 * 4 * sizeof(udword); // Histograms
543  UsedRam += 256 * sizeof(udword); // Link
544 #endif
545  UsedRam += 2 * CURRENT_SIZE * sizeof(udword); // 2 lists of indices
546  return UsedRam;
547 }
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
#define CURRENT_SIZE
udword * RadixSort::RelinquishRanks ( )

Detach mRanks. After this the caller is responsible for freeing this array via delete [] operator.

Definition at line 219 of file IceRevisitedRadix.cc.

References DELETEARRAY, mCurrentSize, mRanks, and mRanks2.

Referenced by mkfit::LayerOfHits::endRegistrationOfHits(), and mkfit::LayerOfHits::suckInHits().

219  {
220  udword* ranks = mRanks;
221  mRanks = nullptr;
223  mCurrentSize = 0;
224  return ranks;
225 }
udword mCurrentSize
Current size of the indices list.
udword * mRanks2
#define DELETEARRAY(x)
Deletes an array.
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
udword * mRanks
Two lists, swapped each pass.
bool RadixSort::Resize ( udword  nb)
private

Resizes the inner lists.

Parameters
nb[in] new size (number of dwords)
Returns
true if success

Definition at line 234 of file IceRevisitedRadix.cc.

References CHECKALLOC, DELETEARRAY, mRanks, and mRanks2.

Referenced by CheckResize().

234  {
235  // Free previously used ram
238 
239  // Get some fresh one
240  mRanks = new udword[nb];
242  mRanks2 = new udword[nb];
244 
245  return true;
246 }
udword * mRanks2
#define DELETEARRAY(x)
Deletes an array.
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
#define CHECKALLOC(x)
udword * mRanks
Two lists, swapped each pass.
RadixSort & RadixSort::Sort ( const udword input,
udword  nb,
RadixHint  hint = RADIX_SIGNED 
)

Main sort routine. This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.

Parameters
input[in] a list of integer values to sort
nb[in] number of values to sort, must be < 2^31
hint[in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values
Returns
Self-Reference

Definition at line 271 of file IceRevisitedRadix.cc.

References CHECK_PASS_VALIDITY, CheckResize(), CREATE_HISTOGRAMS, mps_fire::i, gpuClustering::id, INVALID_RANKS, dqmiolumiharvest::j, mRanks, mRanks2, mTotalCalls, RADIX_SIGNED, RADIX_UNSIGNED, and VALIDATE_RANKS.

Referenced by mkfit::LayerOfHits::endRegistrationOfHits(), mkfit::MkBuilder::import_seeds(), and mkfit::LayerOfHits::suckInHits().

271  {
272  // Checkings
273  if (!input || !nb || nb & 0x80000000)
274  return *this;
275 
276  // Stats
277  mTotalCalls++;
278 
279  // Resize lists if needed
280  CheckResize(nb);
281 
282 #ifdef RADIX_LOCAL_RAM
283  // Allocate histograms & offsets on the stack
284  udword mHistogram[256 * 4];
285  udword* mLink[256];
286 #endif
287 
288  // Create histograms (counters). Counters for all passes are created in one run.
289  // Pros: read input buffer once instead of four times
290  // Cons: mHistogram is 4Kb instead of 1Kb
291  // We must take care of signed/unsigned values for temporal
292  // coherence.... I just have 2 code paths even if just a single
293  // opcode changes. Self-modifying code, someone?
294  if (hint == RADIX_UNSIGNED) {
296  } else {
298  }
299 
300  // Compute #negative values involved if needed
301  udword NbNegativeValues = 0;
302  if (hint == RADIX_SIGNED) {
303  // An efficient way to compute the number of negatives values
304  // we'll have to deal with is simply to sum the 128 last values
305  // of the last histogram. Last histogram because that's the one
306  // for the Most Significant Byte, responsible for the sign. 128
307  // last values because the 128 first ones are related to
308  // positive numbers.
309  udword* h3 = &mHistogram[768];
310  for (udword i = 128; i < 256; i++)
311  NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
312  }
313 
314  // Radix sort, j is the pass number (0=LSB, 3=MSB)
315  for (udword j = 0; j < 4; j++) {
317 
318  // Sometimes the fourth (negative) pass is skipped because all
319  // numbers are negative and the MSB is 0xFF (for example). This
320  // is not a problem, numbers are correctly sorted anyway.
321  if (PerformPass) {
322  // Should we care about negative values?
323  if (j != 3 || hint == RADIX_UNSIGNED) {
324  // Here we deal with positive values only
325 
326  // Create offsets
327  mLink[0] = mRanks2;
328  for (udword i = 1; i < 256; i++)
329  mLink[i] = mLink[i - 1] + CurCount[i - 1];
330  } else {
331  // This is a special case to correctly handle negative
332  // integers. They're sorted in the right order but at
333  // the wrong place.
334 
335  // Create biased offsets, in order for negative numbers to be sorted as well
336  mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
337  for (udword i = 1; i < 128; i++)
338  mLink[i] = mLink[i - 1] + CurCount[i - 1]; // 1 to 128 for positive numbers
339 
340  // Fixing the wrong place for negative values
341  mLink[128] = mRanks2;
342  for (udword i = 129; i < 256; i++)
343  mLink[i] = mLink[i - 1] + CurCount[i - 1];
344  }
345 
346  // Perform Radix Sort
347  ubyte* InputBytes = (ubyte*)input;
348  InputBytes += j;
349  if (INVALID_RANKS) {
350  for (udword i = 0; i < nb; i++)
351  *mLink[InputBytes[i << 2]]++ = i;
353  } else {
354  udword* Indices = mRanks;
355  udword* IndicesEnd = &mRanks[nb];
356  while (Indices != IndicesEnd) {
357  udword id = *Indices++;
358  *mLink[InputBytes[id << 2]]++ = id;
359  }
360  }
361 
362  // Swap pointers for next pass. Valid indices - the most
363  // recent ones - are in mRanks after the swap.
364  udword* Tmp = mRanks;
365  mRanks = mRanks2;
366  mRanks2 = Tmp;
367  }
368  }
369  return *this;
370 }
#define VALIDATE_RANKS
uint16_t *__restrict__ id
signed int sdword
sizeof(sdword) must be 4
Definition: IceTypes.h:51
udword mTotalCalls
Total number of calls to the sort routine.
udword * mRanks2
Input values are signed.
#define INVALID_RANKS
static std::string const input
Definition: EdmProvDump.cc:47
#define CHECK_PASS_VALIDITY(pass)
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
Indices
Definition: EdmEventSize.cc:28
#define CREATE_HISTOGRAMS(type, buffer)
unsigned char ubyte
sizeof(ubyte) must be 1
Definition: IceTypes.h:48
void CheckResize(udword nb)
Input values are unsigned.
udword * mRanks
Two lists, swapped each pass.
RadixSort & RadixSort::Sort ( const float *  input2,
udword  nb 
)

Main sort routine. This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.

Parameters
input[in] a list of floating-point values to sort
nb[in] number of values to sort, must be < 2^31
Returns
Self-Reference
Warning
only sorts IEEE floating-point values

Definition at line 384 of file IceRevisitedRadix.cc.

References CHECK_PASS_VALIDITY, CheckResize(), CREATE_HISTOGRAMS, mps_fire::i, gpuClustering::id, input, INVALID_RANKS, dqmiolumiharvest::j, mRanks, mRanks2, mTotalCalls, and VALIDATE_RANKS.

384  {
385  // Checkings
386  if (!input2 || !nb || nb & 0x80000000)
387  return *this;
388 
389  // Stats
390  mTotalCalls++;
391 
392  udword* input = (udword*)input2;
393 
394  // Resize lists if needed
395  CheckResize(nb);
396 
397 #ifdef RADIX_LOCAL_RAM
398  // Allocate histograms & offsets on the stack
399  udword mHistogram[256 * 4];
400  udword* mLink[256];
401 #endif
402 
403  // Create histograms (counters). Counters for all passes are created
404  // in one run.
405  // Pros: read input buffer once instead of four times
406  // Cons: mHistogram is 4Kb instead of 1Kb
407  //
408  // Floating-point values are always supposed to be signed values, so
409  // there's only one code path there.
410  // Please note the floating point comparison needed for temporal
411  // coherence! Although the resulting asm code is dreadful, this is
412  // surprisingly not such a performance hit - well, I suppose that's
413  // a big one on first generation Pentiums....We can't make
414  // comparison on integer representations because, as Chris said, it
415  // just wouldn't work with mixed positive/negative values....
416  { CREATE_HISTOGRAMS(float, input2); }
417 
418  // Compute #negative values involved if needed
419  udword NbNegativeValues = 0;
420  // An efficient way to compute the number of negatives values we'll
421  // have to deal with is simply to sum the 128 last values of the
422  // last histogram. Last histogram because that's the one for the
423  // Most Significant Byte, responsible for the sign. 128 last values
424  // because the 128 first ones are related to positive numbers.
425  udword* h3 = &mHistogram[768];
426  for (udword i = 128; i < 256; i++)
427  NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
428 
429  // Radix sort, j is the pass number (0=LSB, 3=MSB)
430  for (udword j = 0; j < 4; j++) {
431  // Should we care about negative values?
432  if (j != 3) {
433  // Here we deal with positive values only
435 
436  if (PerformPass) {
437  // Create offsets
438  mLink[0] = mRanks2;
439  for (udword i = 1; i < 256; i++)
440  mLink[i] = mLink[i - 1] + CurCount[i - 1];
441 
442  // Perform Radix Sort
443  ubyte* InputBytes = (ubyte*)input;
444  InputBytes += j;
445  if (INVALID_RANKS) {
446  for (udword i = 0; i < nb; i++)
447  *mLink[InputBytes[i << 2]]++ = i;
449  } else {
450  udword* Indices = mRanks;
451  udword* IndicesEnd = &mRanks[nb];
452  while (Indices != IndicesEnd) {
453  udword id = *Indices++;
454  *mLink[InputBytes[id << 2]]++ = id;
455  }
456  }
457 
458  // Swap pointers for next pass. Valid indices - the most
459  // recent ones - are in mRanks after the swap.
460  udword* Tmp = mRanks;
461  mRanks = mRanks2;
462  mRanks2 = Tmp;
463  }
464  } else {
465  // This is a special case to correctly handle negative values
467 
468  if (PerformPass) {
469  // Create biased offsets, in order for negative numbers
470  // to be sorted as well
471  mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones
472  for (udword i = 1; i < 128; i++)
473  mLink[i] = mLink[i - 1] + CurCount[i - 1]; // 1 to 128 for positive numbers
474 
475  // We must reverse the sorting order for negative numbers!
476  mLink[255] = mRanks2;
477  for (udword i = 0; i < 127; i++)
478  mLink[254 - i] = mLink[255 - i] + CurCount[255 - i]; // Fixing the wrong order for negative values
479  for (udword i = 128; i < 256; i++)
480  mLink[i] += CurCount[i]; // Fixing the wrong place for negative values
481 
482  // Perform Radix Sort
483  if (INVALID_RANKS) {
484  for (udword i = 0; i < nb; i++) {
485  udword Radix = input[i] >> 24; // Radix byte, same as above. AND is useless here (udword).
486  // ### cmp to be killed. Not good. Later.
487  if (Radix < 128)
488  *mLink[Radix]++ = i; // Number is positive, same as above
489  else
490  *(--mLink[Radix]) = i; // Number is negative, flip the sorting order
491  }
493  } else {
494  for (udword i = 0; i < nb; i++) {
495  udword Radix = input[mRanks[i]] >> 24; // Radix byte, same as above. AND is useless here (udword).
496  // ### cmp to be killed. Not good. Later.
497  if (Radix < 128)
498  *mLink[Radix]++ = mRanks[i]; // Number is positive, same as above
499  else
500  *(--mLink[Radix]) = mRanks[i]; // Number is negative, flip the sorting order
501  }
502  }
503  // Swap pointers for next pass. Valid indices - the most
504  // recent ones - are in mRanks after the swap.
505  udword* Tmp = mRanks;
506  mRanks = mRanks2;
507  mRanks2 = Tmp;
508  } else {
509  // The pass is useless, yet we still have to reverse the order of current list if all values are negative.
510  if (UniqueVal >= 128) {
511  if (INVALID_RANKS) {
512  // ###Possible?
513  for (udword i = 0; i < nb; i++)
514  mRanks2[i] = nb - i - 1;
516  } else {
517  for (udword i = 0; i < nb; i++)
518  mRanks2[i] = mRanks[nb - i - 1];
519  }
520 
521  // Swap pointers for next pass. Valid indices - the
522  // most recent ones - are in mRanks after the swap.
523  udword* Tmp = mRanks;
524  mRanks = mRanks2;
525  mRanks2 = Tmp;
526  }
527  }
528  }
529  }
530  return *this;
531 }
#define VALIDATE_RANKS
uint16_t *__restrict__ id
udword mTotalCalls
Total number of calls to the sort routine.
udword * mRanks2
#define INVALID_RANKS
#define input2
Definition: AMPTWrapper.h:159
static std::string const input
Definition: EdmProvDump.cc:47
#define CHECK_PASS_VALIDITY(pass)
unsigned int udword
sizeof(udword) must be 4
Definition: IceTypes.h:52
Indices
Definition: EdmEventSize.cc:28
#define CREATE_HISTOGRAMS(type, buffer)
unsigned char ubyte
sizeof(ubyte) must be 1
Definition: IceTypes.h:48
void CheckResize(udword nb)
udword * mRanks
Two lists, swapped each pass.

Member Data Documentation

udword RadixSort::mCurrentSize
private

Current size of the indices list.

Definition at line 61 of file IceRevisitedRadix.h.

Referenced by CheckResize(), and RelinquishRanks().

udword RadixSort::mNbHits
private

Number of early exits due to coherence.

Definition at line 66 of file IceRevisitedRadix.h.

Referenced by GetNbHits().

udword* RadixSort::mRanks
private

Two lists, swapped each pass.

Definition at line 62 of file IceRevisitedRadix.h.

Referenced by GetRanks(), RelinquishRanks(), Resize(), Sort(), and ~RadixSort().

udword* RadixSort::mRanks2
private

Definition at line 63 of file IceRevisitedRadix.h.

Referenced by GetRecyclable(), RelinquishRanks(), Resize(), Sort(), and ~RadixSort().

udword RadixSort::mTotalCalls
private

Total number of calls to the sort routine.

Definition at line 65 of file IceRevisitedRadix.h.

Referenced by GetNbTotalCalls(), and Sort().