Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configure thread pools size relative to the number of available cores #16303

Closed
wants to merge 1 commit into from

Conversation

wendigo
Copy link
Contributor

@wendigo wendigo commented Feb 28, 2023

Description

Alternative to #16287

It makes it possible to configure threads pools using more sophisticated syntax:

  • [int] (exact number)
  • [float]C - multiplier of available cores (i.e. machine with 24 cores, 2C = 48 threads, 0.1C = 2 threads)

Additional context and related issues

Release notes

( ) This is not user-visible or docs only and no release notes are required.
( ) Release notes are required, please propose a release note for me.
( ) Release notes are required, with the following suggested text:

# Section
* Fix some things. ({issue}`issuenumber`)

@cla-bot cla-bot bot added the cla-signed label Feb 28, 2023
@github-actions github-actions bot added hive Hive connector tests:hive labels Feb 28, 2023
@wendigo wendigo changed the title Adds ThreadsCount record to simplify configuration Configure thread pools size relative to the number of available cores Mar 1, 2023
Copy link
Member

@phd3 phd3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments. Overall I like this generic approach over specific change in #16287, but would also let other maintainers chime in w.r.t whether this should go in airlift (and the syntax)

private int deletionThreads = max(1, getRuntime().availableProcessors() / 2);
private int recoveryThreads = 10;
private int organizationThreads = 5;
private ThreadsCount deletionThreads = ThreadsCount.valueOf("0.5C");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a separate bugfix as looks like previous impl would always cap it to 1? if so, i'd keep it in a separate commit/PR. I'm not sure about whether the previous value was intentional. cc @electrum

@@ -51,13 +49,13 @@ public void testDefaults()
.setOrcTinyStripeThreshold(DataSize.of(8, MEGABYTE))
.setOrcLazyReadSmallRanges(true)
.setOrcNestedLazy(true)
.setDeletionThreads(max(1, getRuntime().availableProcessors() / 2))
.setDeletionThreads("0.5C")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment about max here

@@ -54,7 +50,7 @@
private DataSize maxLocalExchangeBufferSize = DataSize.of(32, Unit.MEGABYTE);
private DataSize maxIndexMemoryUsage = DataSize.of(64, Unit.MEGABYTE);
private boolean shareIndexLoading;
private int maxWorkerThreads = Runtime.getRuntime().availableProcessors() * 2;
private ThreadsCount maxWorkerThreads = ThreadsCount.valueOf("2C");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for many of these, documentation wuold need to be updated right?


import static java.lang.Math.round;

public record ThreadsCount(int threadsCount)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this something that should belong in airlift like Duration/Datasize? @trinodb/maintainers

}

@LegacyConfig("task.shard.max-threads")
@Config("task.max-worker-threads")
public TaskManagerConfig setMaxWorkerThreads(int maxWorkerThreads)
public TaskManagerConfig setMaxWorkerThreads(String maxWorkerThreads)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be able to use ThreadsCount parameter instead of string: https://github.com/airlift/airlift/blob/master/configuration/src/main/java/io/airlift/configuration/ConfigurationFactory.java#L666

is there a reason to do otherwise?

private void assertInvalidValue(String value, String expectedMessage)
{
try {
ThreadsCount.valueOf(value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use assertThatThrownBy

@phd3 phd3 requested a review from a team March 1, 2023 17:14
@wendigo
Copy link
Contributor Author

wendigo commented Mar 1, 2023

@phd3 I agree that this could be a part of the airlift and applied there as well

@findepi
Copy link
Member

findepi commented Mar 1, 2023

I am concerned about additional complexity this introduced. Is it outweighed with value added?
for scripting systems like maven it's quite practical to set -T 1C without thinking much about cores... (Actually, even for maven it's not enough. I use # threads being 1C - 1 to maintain MacOS responsiveness while running a build)
For Trino, i think people know where they deploy and if they need to tune, they can do it without issue.

(this doesn't mean we shouldn't auto-tune. We should auto-tune out-of-the-box, but i understand this is now what this PR is doing)

@electrum
Copy link
Member

electrum commented Mar 2, 2023

I like this in general. There are probably various configs we could update to have better defaults.

I don’t like the “C2” syntax since it’s easy to mix up with “2C”. I also question if this is needed. What’s the use case? Do we ever require power of two? If we do, we could make rounding automatic for those?

@wendigo
Copy link
Contributor Author

wendigo commented Mar 2, 2023

@electrum there are cases when power of two size is required and actually validated. What would be a better syntax?

}

private static final String PER_CORE_SUFFIX = "C";
private static final String PER_CORE_NEXT_POWER_OF_2_SUFFIX = "C2";
Copy link
Member

@sopel39 sopel39 Mar 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's confusing as it suggest it's 2 number of cores rather than pow of two. See how we deal with it in io.trino.execution.TaskManagerConfig#taskConcurrency.

I think user should just provide number that is power of two. These config properties shouldn't be touched by user too much anyway if they don't know what they are doing.

@phd3
Copy link
Member

phd3 commented Mar 7, 2023

@wendigo so I read this is as we generally agree that this can move into airlift.

Based on some comments above - looks like we still need to discuss on the syntax simplification especially around C2. I like the suggestion in #16303 (comment). @findepi do you feel strongly about the overhead if somehow the C2 scenario is simplified?

@wendigo
Copy link
Contributor Author

wendigo commented Mar 29, 2023

Extracted to airlift/units#31

@wendigo
Copy link
Contributor Author

wendigo commented Jul 17, 2023

@phd3 @Praveen2112 @sopel39 this type is now coming from airlift/units

New type was introduced in the airlift/units 1.10
@github-actions github-actions bot added the jdbc Relates to Trino JDBC driver label Jul 17, 2023
// newer units version in JDBC due to different JDK target.
// It is temporary solution until client and JDBC are moved to JDK 11+.
// This class is added to test classes, so it won't be a part of the jdbc driver.
public class ThreadCount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we need this copy?
plase remove

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jdk 8 target and newer units is on 11

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i know. but trino-jdbc should avoid having classes in io.airlift

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It’s the matter of test scope

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this class resides in trino-jdbc tests, it is unused there, and must remain API-compatible with the newly added ThreadCount class in units. Does this sounds like we're doing something wrong here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. Keeping JDBC on JDK 8 which prohibits upgrading dependencies like airlift units

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i understand correctly, trino-jdbc ships units 1.7 for its own use and it downgrades units version for test scope resulting in NoClassDefFoundError when we try to start trino server.

unless maven allows us to package units 1.7 but still use a newer version for test classpath, i see the following options:

  • stop using airlift units in trino-jdbc (perhaps copying & repackaging necessary classed if this is indeed warranted)
  • move jdbc tests that require trino server to a separate module, where we will use modern units.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving tests seems like a better option

@findepi
Copy link
Member

findepi commented Sep 21, 2023

@wendigo i'd suggest to split this PR and configure eg task.max-worker-threads first and then proceed with other configs.
things like legacy raptor's backup config will want a different reviewers audience than the core driver processing configuration.

@findepi
Copy link
Member

findepi commented Sep 21, 2023

I tried using ThreadCount internally and realized it's not really a value object. It's just a parser String -> int.
I think i would replace the class with a parser:

public class ThreadCountParser
{
    private static final String PER_CORE_SUFFIX = "C";
    private static final Supplier<Integer> AVAILABLE_PROCESSORS = memoize(MachineInfo::getAvailablePhysicalProcessorCount);
    public static final ThreadCountParser DEFAULT = new ThreadCountParser(AVAILABLE_PROCESSORS);

    private final Supplier<Integer> coreCount;

    @VisibleForTesting
    ThreadCountParser(Supplier<Integer> coreCount);

    public int parse(String value);
}

this would result in simpler code, simpler concepts

added bonus?

the parser would belong to Trino codebase (or airlift), not units
and thus there would be no testing issue for trino-jdbc

cc @wendigo @losipiuk

@@ -53,7 +51,7 @@ public class TaskManagerConfig
private DataSize maxLocalExchangeBufferSize = DataSize.of(128, Unit.MEGABYTE);
private DataSize maxIndexMemoryUsage = DataSize.of(64, Unit.MEGABYTE);
private boolean shareIndexLoading;
private int maxWorkerThreads = Runtime.getRuntime().availableProcessors() * 2;
private ThreadCount maxWorkerThreads = ThreadCount.valueOf("2C");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is two separate changes

  1. the main one per PR title: allowing to configure n in n * number of cores formula
  2. how the "number of cores" is determined

I think the changes should go as separate things. The (1) is obvious, but the (2) is tricky and needs to be thoroughly code commented

int availableProcessorCount = Runtime.getRuntime().availableProcessors();
int totalPhysicalProcessorCount = availableProcessorCount;
if ("amd64".equals(osArch) || "x86_64".equals(osArch)) {
OptionalInt procInfo = tryReadFromProcCpuinfo();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is it better than Runtime.getRuntime().availableProcessors() and why take min of the two instead of just using "the better one"?
This should be documented.

}
}

// cap available processor count to container cpu quota (if there is any).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why container quota is inspected for certain architectures only?

@wendigo wendigo closed this Nov 23, 2023
@wendigo wendigo deleted the serafin/add-threads-count branch November 23, 2023 19:14
findepi added a commit to findepi/trino that referenced this pull request Feb 20, 2024
Worker threads defaults to 2*#cores. This commit allows configuration to
be #cores based too.

Extracted from trinodb#16303

Co-authored-by: Mateusz "Serafin" Gajewski <[email protected]>
findepi added a commit to findepi/trino that referenced this pull request Feb 20, 2024
Worker threads defaults to 2*#cores. This commit allows configuration to
be #cores based too.

Extracted from trinodb#16303

Co-authored-by: Mateusz "Serafin" Gajewski <[email protected]>
findepi added a commit that referenced this pull request Feb 21, 2024
Worker threads defaults to 2*#cores. This commit allows configuration to
be #cores based too.

Extracted from #16303

Co-authored-by: Mateusz "Serafin" Gajewski <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla-signed hive Hive connector jdbc Relates to Trino JDBC driver
Development

Successfully merging this pull request may close these issues.

6 participants