/*
*
      
_______
                       
_____
   
_____ _____
  

*
     
|__
   
__|
                     
|
  
__ \ / ____|__ \
 

*
        
| | __ _ _ __ ___
  
______| || | (___ | |__) |
*
        
| |/ _` | '__/ __|/ _ \/ __| |
  
| |\___ \|___/
 

*
        
| | (_| | |
  
\__ \ (_) \__ \ |__| |____) | |
     

*
        
|_|\__,_|_|
  
|___/\___/|___/_____/|_____/|_|
     

*
                                                         

* -------------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at IPEM, University Ghent
*
  

* -------------------------------------------------------------
*
*
  
Info:
 
http://0110.be/tag/TarsosDSP
*
  
Github:
 
https://github.com/JorenSix/TarsosDSP
*
  
Releases:
 
http://0110.be/releases/TarsosDSP/
*
  

*
  
TarsosDSP includes modified source code by various authors,
*
  
for credits and info, see README.
*
 

*/


/* ***** BEGIN LICENSE BLOCK *****
 
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
*
 
* The contents of this file are subject to the Mozilla Public License Version
 
* 1.1 (the "License"); you may not use this file except in compliance with
 
* the License. You may obtain a copy of the License at
 
* http://www.mozilla.org/MPL/
 
*
 
* Software distributed under the License is distributed on an "AS IS" basis,
 
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
* for the specific language governing rights and limitations under the
 
* License.
 
*
 
* The Original Code is Parallel Colt.
 
*
 
* The Initial Developer of the Original Code is
 
* Piotr Wendykier, Emory University.
 
* Portions created by the Initial Developer are Copyright (C) 2007-2009
 
* the Initial Developer. All Rights Reserved.
 
*
 
* Alternatively, the contents of this file may be used under the terms of
 
* either the GNU General Public License Version 2 or later (the "GPL"), or
 
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
* in which case the provisions of the GPL or the LGPL are applicable instead
 
* of those above. If you wish to allow use of your version of this file only
 
* under the terms of either the GPL or the LGPL, and not to allow others to
 
* use your version of this file under the terms of the MPL, indicate your
 
* decision by deleting the provisions above and replace them with the notice
 
* and other provisions required by the GPL or the LGPL. If you do not delete
 
* the provisions above, a recipient may use your version of this file under
 
* the terms of any one of the MPL, the GPL or the LGPL.
 
*
 
* ***** END LICENSE BLOCK ***** */

package be.tarsos.dsp.util;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

/**
 
* Concurrency utilities.
 
*
 
* @author Piotr Wendykier (piotr.wendykier@gmail.com)
 
*/

public class ConcurrencyUtils {
    
/**
     
* Thread pool.
     
*/
    
private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(new CustomThreadFactory(new CustomExceptionHandler()));

    
private static int THREADS_BEGIN_N_1D_FFT_2THREADS = 8192;

    
private static int THREADS_BEGIN_N_1D_FFT_4THREADS = 65536;

    
private static int THREADS_BEGIN_N_2D = 65536;

    
private static int THREADS_BEGIN_N_3D = 65536;

    
private static int NTHREADS = prevPow2(getNumberOfProcessors());

    
private ConcurrencyUtils() {

    
}

    
private static class CustomExceptionHandler implements Thread.UncaughtExceptionHandler {
        
public void uncaughtException(Thread t, Throwable e) {
            
e.printStackTrace();
        
}

    
}

    
private static class CustomThreadFactory implements ThreadFactory {
        
private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory();

        
private final Thread.UncaughtExceptionHandler handler;

        
CustomThreadFactory(Thread.UncaughtExceptionHandler handler) {
            
this.handler = handler;
        
}

        
public Thread newThread(Runnable r) {
            
Thread t = defaultFactory.newThread(r);
            
t.setUncaughtExceptionHandler(handler);
            
return t;
        
}
    
};

    
/**
     
* Returns the number of available processors.
     
*
 

     
* @return number of available processors
     
*/

    
public static int getNumberOfProcessors() {
        
return Runtime.getRuntime().availableProcessors();
    
}

    
/**
     
* Returns the current number of threads.
     
*
 

     
* @return the current number of threads.
     
*/

    
public static int getNumberOfThreads() {
        
return NTHREADS;
    
}

    
/**
     
* Sets the number of threads. If n is not a power-of-two number, then the
     
* number of threads is set to the closest power-of-two number less than n.
     
*
 

     
* @param n
     
*/

    
public static void setNumberOfThreads(int n) {
        
NTHREADS = prevPow2(n);
    
}

    
/**
     
* Returns the minimal size of 1D data for which two threads are used.
     
*
 

     
* @return the minimal size of 1D data for which two threads are used
     
*/

    
public static int getThreadsBeginN_1D_FFT_2Threads() {
        
return THREADS_BEGIN_N_1D_FFT_2THREADS;
    
}

    
/**
     
* Returns the minimal size of 1D data for which four threads are used.
     
*
 

     
* @return the minimal size of 1D data for which four threads are used
     
*/

    
public static int getThreadsBeginN_1D_FFT_4Threads() {
        
return THREADS_BEGIN_N_1D_FFT_4THREADS;
    
}

    
/**
     
* Returns the minimal size of 2D data for which threads are used.
     
*
 

     
* @return the minimal size of 2D data for which threads are used
     
*/

    
public static int getThreadsBeginN_2D() {
        
return THREADS_BEGIN_N_2D;
    
}

    
/**
     
* Returns the minimal size of 3D data for which threads are used.
     
*
 

     
* @return the minimal size of 3D data for which threads are used
     
*/

    
public static int getThreadsBeginN_3D() {
        
return THREADS_BEGIN_N_3D;
    
}

    
/**
     
* Sets the minimal size of 1D data for which two threads are used.
     
*
 

     
* @param n
     
*
            
the minimal size of 1D data for which two threads are used
     
*/

    
public static void setThreadsBeginN_1D_FFT_2Threads(int n) {
        
if (n < 512) {
            
THREADS_BEGIN_N_1D_FFT_2THREADS = 512;
        
} else {
            
THREADS_BEGIN_N_1D_FFT_2THREADS = n;
        
}
    
}

    
/**
     
* Sets the minimal size of 1D data for which four threads are used.
     
*
 

     
* @param n
     
*
            
the minimal size of 1D data for which four threads are used
     
*/

    
public static void setThreadsBeginN_1D_FFT_4Threads(int n) {
        
if (n < 512) {
            
THREADS_BEGIN_N_1D_FFT_4THREADS = 512;
        
} else {
            
THREADS_BEGIN_N_1D_FFT_4THREADS = n;
        
}
    
}

    
/**
     
* Sets the minimal size of 2D data for which threads are used.
     
*
 

     
* @param n
     
*
            
the minimal size of 2D data for which threads are used
     
*/

    
public static void setThreadsBeginN_2D(int n) {
        
THREADS_BEGIN_N_2D = n;
    
}

    
/**
     
* Sets the minimal size of 3D data for which threads are used.
     
*
 

     
* @param n
     
*
            
the minimal size of 3D data for which threads are used
     
*/

    
public static void setThreadsBeginN_3D(int n) {
        
THREADS_BEGIN_N_3D = n;
    
}

    
/**
     
* Resets the minimal size of 1D data for which two and four threads are
     
* used.
     
*/

    
public static void resetThreadsBeginN_FFT() {
        
THREADS_BEGIN_N_1D_FFT_2THREADS = 8192;
        
THREADS_BEGIN_N_1D_FFT_4THREADS = 65536;
    
}

    
/**
     
* Resets the minimal size of 2D and 3D data for which threads are used.
     
*/

    
public static void resetThreadsBeginN() {
        
THREADS_BEGIN_N_2D = 65536;
        
THREADS_BEGIN_N_3D = 65536;
    
}

    
/**
     
* Returns the closest power-of-two number greater than or equal to x.
     
*
 

     
* @param x
     
* @return the closest power-of-two number greater than or equal to x
     
*/

    
public static int nextPow2(int x) {
        
if (x < 1)
            
throw new IllegalArgumentException("x must be greater or equal 1");
        
if ((x & (x - 1)) == 0) {
            
return x; // x is already a power-of-two number
 

        
}
        
x |= (x >>> 1);
        
x |= (x >>> 2);
        
x |= (x >>> 4);
        
x |= (x >>> 8);
        
x |= (x >>> 16);
        
x |= (x >>> 32);
        
return x + 1;
    
}

    
/**
     
* Returns the closest power-of-two number less than or equal to x.
     
*
 

     
* @param x
     
* @return the closest power-of-two number less then or equal to x
     
*/

    
public static int prevPow2(int x) {
        
if (x < 1)
            
throw new IllegalArgumentException("x must be greater or equal 1");
        
return (int) Math.pow(2, Math.floor(Math.log(x) / Math.log(2)));
    
}

    
/**
     
* Checks if x is a power-of-two number.
     
*
 

     
* @param x
     
* @return true if x is a power-of-two number
     
*/

    
public static boolean isPowerOf2(int x) {
        
if (x <= 0)
            
return false;
        
else
            
return
(x & (x - 1)) == 0;
    
}

    
/**
     
* Causes the currently executing thread to sleep (temporarily cease
     
* execution) for the specified number of milliseconds.
     
*
 

     
* @param millis
     
*/

    
public static void sleep(long millis) {
        
try {
            
Thread.sleep(5000);
        
} catch (InterruptedException e) {
            
e.printStackTrace();
        
}
    
}

    
/**
     
* Submits a Runnable task for execution and returns a Future representing
     
* that task.
     
*
 

     
* @param task a Runnable task for execution
     
* @return a Future representing the task
     
*/

    
public static Future<?> submit(Runnable task) {
        
return THREAD_POOL.submit(task);
    
}

    
/**
     
* Waits for all threads to complete computation.
     
*
 

     
* @param futures
     
*/

    
public static void waitForCompletion(Future<?>[] futures) {
        
int size = futures.length;
        
try {
            
for (int j = 0; j < size; j++) {
                
futures[j].get();
            
}
        
} catch (ExecutionException ex) {
            
ex.printStackTrace();
        
} catch (InterruptedException e) {
            
e.printStackTrace();
        
}
    
}
}