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

Switch ThreadId to an opaque value type. #7330

Merged
merged 18 commits into from
Jul 1, 2019
Merged

Switch ThreadId to an opaque value type. #7330

merged 18 commits into from
Jul 1, 2019

Conversation

fowles
Copy link
Contributor

@fowles fowles commented Jun 19, 2019

Description: ThreadId does not need to be an abstract class and that just interferes
with using them as keys in hashtables.

For an explanation of how to fill out the fields, please see the relevant section
in PULL_REQUESTS.md

Risk Level: Low
Testing: Unit
Docs Changes: N/A
Release Notes: N/A

@jmarantz
Copy link
Contributor

Actually it does need to be an abstract type. Please read #6825 (comment)

And it's not difficult to make them hashable. Just define a pure hash() method and supply a posix impl.

I don't think it would be hard to revive/replicate #6825 and just make it work. Can we go in that direction instead of concretizing it. Happy to help if there is trouble.

@jmarantz
Copy link
Contributor

Oh I just correlated who you are ... is there some reason you wanted to go down this route rather than just make the object hashable?

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

The idea of a full virtual hierachy for something that is an int64 (or smaller) on all platforms seems wasteful. Also, it has harder than just adding a hash virtual, you will need custom Hasher and Eq operators too. Making this a value makes it that much simpler to work with.

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

Also, this is not a pthread_id it is a https://linux.die.net/man/2/gettid or a http://www.manpagez.com/man/3/pthread_threadid_np/ both of which are == comparable if I am reading it correctly...

@jmarantz
Copy link
Contributor

jmarantz commented Jun 20, 2019

Current impl in posix is in source/common/common/posix/thread_impl.cc and is:

int64_t getCurrentThreadId() {
#ifdef __linux__
  return static_cast<int64_t>(syscall(SYS_gettid));
#elif defined(__APPLE__)
  uint64_t tid;
  pthread_threadid_np(nullptr, &tid);
  return tid;
#else
#error "Enable and test pthread id retrieval code for you arch in pthread/thread_impl.cc"
#endif
}

So the linux version calls syscall(SYS_gettid)) .

Doc for gettid() I found is https://linux.die.net/man/2/gettid : which is pid_t gettid(void); and says:

The thread ID returned by this call is not the same thing as a POSIX thread ID (i.e., the opaque value returned by pthread_self(3)).

So that's where I got to pid_t from. I don't know of a platform where you couldn't render the pid_t as a uint64_t but the doc seems specific that you ought not to assume that, if you want your code to be portable. There were some efforts a while back to get Envoy working on Windows, though they seem to be dormant at the moment.

My feeling is that it's not maximally efficient to have to have a virtual class around a uint64_t but given Envoy's thread-per-core model (https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310), there may be hundreds but not thousands of threads, so this is not going to amount to any measurable cost in memory consumption, and it might make porting life easier for someone.

RE Hash and Eq functors; I don't think you need an Eq functor if we add operator== to the class; it just works....realizing now who I'm talking to; is supplying a Hash but not an Eq to absl::flat_hash_map -- is that something that currently works but is not really supported? Obviously it's not hard to work around if we need to specify both.

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

If you want a table of the thing you will need to do:

struct Hash {
  size_t operator()(const ThreadIdPtr& p) const {
    return absl::Hash<ThreadId>{}(*p);
  }
};

struct Eq {
  bool operator()(const ThreadIdPtr& lhs, const ThreadIdPtr& rhs) const {
     // down cast and compare
  }
};

absl::flat_hash_map<ThreadIdPtr, V, Hash, Eq> m;

you definitely don't want the default Eq because it will do pointer comparison for that case

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

I am a bit confused, #6825 (comment) specifically is talking about https://linux.die.net/man/3/pthread_self which is different from what the implementation you quoted use. My point is the implementation doesn't use the thing you linked in that comment and uses something that is == comparable (I think)

@jmarantz
Copy link
Contributor

Good point; I was thinking about keeping a table of the objects instead of pointers to them, but that's hard since ThreadId is abstract :) OK we need the Eq functor too.

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

I am not wed to this change, but the extra indirections felt easy to remove and the result is an Id that you could keep by value in tables and have everything be much cleaner for.

@jmarantz
Copy link
Contributor

I think you're right; I was confused about pthread_self being relevant here; it looks like in posix pid_t is defined as a signed integer type, and in Windows it's a DWORD.

One minor annoyance is that if we change the API we'll need to change the windows impl in source/common/common/win32/thread_impl.cc and I don't know who's set up to test that, and it's not in CI. But I guess we could just break it and let people who work on Windows sort it out later until they can get into CI. @sesmith177 are you still looking at Windows stuff? Last couple of times I pinged you you didn't respond.

With regards to this PR you'll have to sort out DCO: https://github.com/envoyproxy/envoy/blob/master/CONTRIBUTING.md#dco-sign-your-work as well as fixing the format errors from CI and the compile error in compile_time_options.

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

I will sort out those details tomorrow! Cheers

@sesmith177
Copy link
Member

@jmarantz yeah, I left Pivotal a couple months ago and so am no longer working on the port of Envoy to Windows.

Since a DWORD is an unsigned 32-bit integer, it may be OK to just store it an int64, but it may just be safer to typedef it in include/envoy/thread/thread.h or something

@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

The static_cast<int64_t> for the DWORD is pretty easy and guaranteed to be safe. The sentinel I am using is out of range for a DWORD and thus guaranteed to be safe. I am less clear on if INT_MIN is safe sentinel for posix systems, but my guess is yes ;)

@jmarantz
Copy link
Contributor

jmarantz commented Jun 20, 2019

I raised an issue on the slack (envoy-dev) about what to do about the windows code maintenance:

Hi all -- it looks like there is no one working currently on Envoy for Windows, but there's a lot of support code in there which is untestable by (AFAIK) anyone currently working in the codebase. What do folks think we should do with it...I'm left sometimes speculating on the windows portability implications of various PRs.

fowles added 2 commits June 20, 2019 14:34
ThreadId does not need to be an abstract class and that just interferes
with using them as keys in hashtables.

Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
@fowles
Copy link
Contributor Author

fowles commented Jun 20, 2019

fixed the formatting and DCO stuff

Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

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

generally looks fine; just wanted to see a hash-table definition come out of this effort as well :)

Also I will + in an Envoy Windows developer (Matt Horan) once he gives me his github ID, which I could not figure out.

include/envoy/thread/thread.h Show resolved Hide resolved
source/common/singleton/manager_impl.cc Outdated Show resolved Hide resolved
fowles added 3 commits June 24, 2019 13:16
Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
@wrowe
Copy link
Contributor

wrowe commented Jun 26, 2019

Hi there, note that on master I'm blocked on issue 7357 to have Win32 compile, so if someone has recommendations for a clean fix to the use of absl against an older stdc++ style str implementation, that should jumpstart my ability to inspect this fix.

@jmarantz
Copy link
Contributor

@wrowe @mhoran does it make sense to proceed with merging this PR with the somewhat speculative win32 implementation, and leave it in your hands to clean it up as we get win32 into CI?

@fowles your clang-tidy errors appear to be in windows-related files where clang can't find windows.h etc. @lizan how do we work around this?

The other CI failures may be known flakes and we can trigger a retest. I still need to do a final pass over the code. Thanks for pushing through this Matt.

/retest

@repokitteh-read-only
Copy link

🔨 rebuilding ci/circleci: tsan (failed build)
🔨 rebuilding ci/circleci: clang_tidy (failed build)
🔨 rebuilding ci/circleci: coverage (failed build)

🐱

Caused by: a #7330 (comment) was created by @jmarantz.

see: more, trace.

@jmarantz
Copy link
Contributor

/azp run

@jmarantz
Copy link
Contributor

@envoyproxy/senior-maintainers over to you for a final pass.

@alyssawilk
Copy link
Contributor

@fowles looks like you need one more clang tidy pass?
regarding maintainers arguably we're supposed to have a non-googler. @lizan would you be up for taking this one?

@jmarantz
Copy link
Contributor

I don't think clang-tidy can be fixed for this PR as the PR includes windows-specific files, for which clang-tidy cannot find includes.

@jmarantz
Copy link
Contributor

Actually he can't fix the errors but he could fix the warnings:

/build/tmp/_bazel_bazel/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/source/common/common/posix/thread_impl.cc:27:34: warning: pass by value and use std::move [modernize-pass-by-value]
ThreadImplPosix::ThreadImplPosix(std::function<void()> thread_routine)
                                 ^
/build/tmp/_bazel_bazel/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/source/common/common/posix/thread_impl.cc:28:23: warning: parameter 'thread_routine' is passed by value and only copied once; consider moving it to avoid unnecessary copies [performance-unnecessary-value-param]
    : thread_routine_(thread_routine) {
                      ^
                      std::move(    )
/build/tmp/_bazel_bazel/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/source/server/watchdog_impl.h:23:20: warning: std::move of the variable 'thread_id' of the trivially-copyable type 'Thread::ThreadId' has no effect; remove std::move() [performance-move-const-arg]
      : thread_id_(std::move(thread_id)), time_source_(tsource),
                   ^~~~~~~~~~         ~
/build/tmp/_bazel_bazel/b570b5ccd0454dc9af9f65ab1833764d/execroot/envoy/test/mocks/server/mocks.h:183:3: warning: annotate this function with 'override' or (rarely) 'final' [modernize-use-override]
  ~MockGuardDog();
  ^

@alyssawilk
Copy link
Contributor

Ah, that's what I get for commenting without reading the full thread.
Well possibly @lizan can help with that too ;-)
We should keep an eye on how often that happens - it's the first I've seen and we obviously don't want to get in a situation where Matt/Harvey have to regularly force-merge because of over-enthusiastic tidy

fowles added 2 commits June 27, 2019 14:35
@fowles
Copy link
Contributor Author

fowles commented Jun 27, 2019

fixed clang-tidy warnings and pulled from head

jmarantz
jmarantz previously approved these changes Jun 27, 2019
@alyssawilk
Copy link
Contributor

Ah, lizan is out this week. Well as it's going to require Matt's force-merge anyway, @mattklein123 can you take a look?

@mattklein123 mattklein123 self-assigned this Jul 1, 2019
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thanks, looks great with some tiny nits.

/wait

include/envoy/thread/thread.h Outdated Show resolved Hide resolved
}

private:
int64_t id_;
Copy link
Member

Choose a reason for hiding this comment

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

nit: const

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we don't want this. As it stands, this is value type that can be copied and assigned normally. If we make this const we lost assignment

source/common/singleton/manager_impl.h Outdated Show resolved Hide resolved
source/common/singleton/manager_impl.h Outdated Show resolved Hide resolved
source/server/watchdog_impl.h Outdated Show resolved Hide resolved
Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
@fowles
Copy link
Contributor Author

fowles commented Jul 1, 2019

Pulled from latest mainline, merged, made most of the changes requested

mattklein123
mattklein123 previously approved these changes Jul 1, 2019
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thank you!

@mattklein123
Copy link
Member

Sorry can you fix format?

/wait

Signed-off-by: Matt Kulukundis <matt.fowles@gmail.com>
@fowles
Copy link
Contributor Author

fowles commented Jul 1, 2019

format fixed

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants