net.sf.eBus.config.ThreadAffinity Maven / Gradle / Ivy
//
// Copyright 2021 Charles W. Rapp
//
// Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package net.sf.eBus.config;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import net.openhft.affinity.AffinityLock;
import net.openhft.affinity.AffinityStrategies;
import net.sf.eBus.config.ThreadAffinityConfigure.AffinityType;
/**
* Provides interface to
* OpenHFT Thread Affinity Library
* based on a given {@link ThreadAffinityConfigure}. The idea is
* that by binding a thread to a core thread performance is
* improved. But this improvement can only be realized if the
* core is isolated from operating system use. Otherwise the
* thread still faces losing its core to the OS, having to wait
* to gain the core again with its cache wrecked by the OS
* thread.
*
* Please see {@link ThreadAffinityConfigure} for a detailed
* discussion on how to configure thread affinity.
*
*
* This class is designed for use with
* {@code net.sf.eBus.net.SelectorThread} and
* {@code net.sf.eBus.net.client.EClient.RQThread} both of which
* may be bound to a core. This would normally be done when the
* thread is configured as spinning.
*
*
* @see ThreadAffinityConfigure
*
* @author Charles W. Rapp
*/
public final class ThreadAffinity
{
//---------------------------------------------------------------
// Member data.
//
//-----------------------------------------------------------
// Statics.
//
/**
* Locks CPU affinity lock process to prevent concurrent
* acquisition which will cause failures.
*/
private static final Lock sAcquisitionLock =
new ReentrantLock();
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* Private constructor to prevent instantiation.
*/
private ThreadAffinity()
{}
//
// end of Constructors.
//-----------------------------------------------------------
/**
* Returns an OpenHFT thread affinity lock.
* @param config
* @return thread affinity lock. This lock should be
* {@link AffinityLock#release() released} when the thread
* stops.
* @throws IllegalStateException
* if {@code config.affinityType} is
* {@code AffinityType.CPU_STRATEGIES} which requires an
* existing {@code AffinityLock} to work.
*
* @see #acquireLock(AffinityLock, ThreadAffinityConfigure)
*/
public static AffinityLock acquireLock(final ThreadAffinityConfigure config)
{
final AffinityType type = config.affinityType();
final AffinityLock retval;
if (type == AffinityType.CPU_STRATEGIES)
{
throw (
new IllegalStateException(
"affinity lock acquisition using strategies requires an existing lock"));
}
sAcquisitionLock.lock();
try
{
switch (type)
{
case ANY_CORE:
retval = AffinityLock.acquireCore();
break;
case ANY_CPU:
retval = AffinityLock.acquireLock();
break;
case CPU_ID:
retval =
AffinityLock.acquireLock(config.cpuId());
break;
default:
retval =
AffinityLock.acquireLockLastMinus(
config.cpuOffset());
}
if (config.bindFlag())
{
retval.bind(config.wholeCoreFlag());
}
}
finally
{
sAcquisitionLock.unlock();
}
return (retval);
} // end of acquireLock(ThreadAffinityConfigure)
/**
* Returns an OpenHFT thread affinity lock based on an
* existing lock and CPU strategy configuration. The idea
* is OpenHFT will select a CPU based on the existing lock's
* CPU and the CPU selection strategies. Please not that the
* final strategy is {@link AffinityStrategies#ANY} allowing
* any CPU to be chosen if no available CPU matches the
* previous strategies.
* @param lock existing affinity lock.
* @param config CPU selection strategy.
* @return thread affinity lock. This lock should be
* {@link AffinityLock#release() released} when the thread
* stops.
* @throws NullPointerException
* if {@code lock} or {@code config} is {@code null}.
* @throws IllegalArgumentException
* if {@code config} affinity type is not
* {@code AffinityType.CPU_STRATEGIES}.
*
* @see #acquireLock(ThreadAffinityConfigure)
*/
public static AffinityLock acquireLock(final AffinityLock lock,
final ThreadAffinityConfigure config)
{
final AffinityType type = config.affinityType();
final AffinityLock retval;
Objects.requireNonNull(lock, "lock is null");
if (type != AffinityType.CPU_STRATEGIES)
{
throw (
new IllegalArgumentException(
String.format(
"invalid affinity type %s, must be %s",
type,
AffinityType.CPU_STRATEGIES)));
}
sAcquisitionLock.lock();
try
{
final List strategies =
config.strategies();
retval =
lock.acquireLock(
strategies.toArray(
new AffinityStrategies[strategies.size()]));
if (config.bindFlag())
{
retval.bind(config.wholeCoreFlag());
}
}
finally
{
sAcquisitionLock.unlock();
}
return (retval);
} // end of acquireLock(AffinityLock,ThreadAffinityConfigure)
} // end of class ThreadAffinity
© 2015 - 2025 Weber Informatics LLC | Privacy Policy