www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why are globals set to tls by default? and why is fast code ugly by

reply ryuukk_ <ryuukk.dev gmail.com> writes:
Hi,

It's common knowledge that accessing tls global is slow 
http://david-grs.github.io/tls_performance_overhead_cost_linux/

What i do not understand is the reasoning behind choosing tls 
global by default in D

What i find even more weird is writing fast code is ugly in D

Look at this ugly code

```D
__gshared int fast_code_ugly;
```

It should be the opposite

Slow code ugly
Fast code beautiful

What can be done about it?

Renaming ``__gshared``

``shared`` is even more ugly since everything must be shared 
afterwards

I would have prefered if i had to manually set things to tls

```D
 tls int slow_code_ugly;
```

Even C does it better: 
https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html
Mar 26 2023
next sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
Perhaps in ``-betterC`` tls vars should be annotated with 
`` tls``, and the default is not tls just like in C?
Mar 26 2023
parent ryuukk_ <ryuukk.dev gmail.com> writes:
With -betterC it's broken for 3 years btw:

https://issues.dlang.org/show_bug.cgi?id=20737
Mar 26 2023
prev sibling next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Having TLS by default is actually quite desirable if you like your code 
to be safe without having to do anything extra.

As soon as you go into global to the process memory, you are responsible 
for synchronization. Ensuring that the state is what you want it to be.

Keep in mind that threads didn't exist when C was created. They could 
not change their approach without breaking everyone's code. So what they 
do is totally irrelevant unless its 1980.

I think its the correct way around. You can't accidentally cause memory 
safety issues. You must explicitly opt-into the ability to mess up your 
programs state.
Mar 26 2023
next sibling parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 Having TLS by default is actually quite desirable if you like 
 your code to be safe without having to do anything extra.

 As soon as you go into global to the process memory, you are 
 responsible for synchronization. Ensuring that the state is 
 what you want it to be.

 Keep in mind that threads didn't exist when C was created. They 
 could not change their approach without breaking everyone's 
 code. So what they do is totally irrelevant unless its 1980.

 I think its the correct way around. You can't accidentally 
 cause memory safety issues. You must explicitly opt-into the 
 ability to mess up your programs state.
It's never desirable to have it by default, the consensus should be: let the developer make the choice, currently the consensus is to punish the developer who want to make the choice Golang doesn't even have thread local storage, yet they do very well D doesn't have coroutines, D doesn't do anything special, it just forces you to uglyfy your code to opt out ``__gshared`` is ugly to write, ugly to read, there must be a better solution
Mar 26 2023
parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 26 March 2023 at 20:36:37 UTC, ryuukk_ wrote:
 Golang doesn't even have thread local storage, yet they do very 
 well
Go doesn't have a solution to preventing data races at compile time, they just say don't share memory. But what if you accidentally share memory? That is *very* easy to do in Go. You and your users are out of luck. All you can do is run the race detector and pray that you happen to test all the code paths with it that might have data races:
 The race detector only finds races that happen at runtime, so 
 it can't find races in code paths that are not executed
https://go.dev/doc/articles/race_detector
Mar 31 2023
parent ryuukk_ <ryuukk.dev gmail.com> writes:
On Friday, 31 March 2023 at 10:32:53 UTC, Nick Treleaven wrote:
 On Sunday, 26 March 2023 at 20:36:37 UTC, ryuukk_ wrote:
 Golang doesn't even have thread local storage, yet they do 
 very well
Go doesn't have a solution to preventing data races at compile time, they just say don't share memory. But what if you accidentally share memory? That is *very* easy to do in Go. You and your users are out of luck. All you can do is run the race detector and pray that you happen to test all the code paths with it that might have data races:
 The race detector only finds races that happen at runtime, so 
 it can't find races in code paths that are not executed
https://go.dev/doc/articles/race_detector
If you want TLS in GO, you specify that you need a TLS variable, just like every sane languages Go went the smart route on top of having goroutines, making it superior to what ever D offer
Mar 31 2023
prev sibling next sibling parent IGotD- <nise nise.com> writes:
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 Having TLS by default is actually quite desirable if you like 
 your code to be safe without having to do anything extra.

 As soon as you go into global to the process memory, you are 
 responsible for synchronization. Ensuring that the state is 
 what you want it to be.

 Keep in mind that threads didn't exist when C was created. They 
 could not change their approach without breaking everyone's 
 code. So what they do is totally irrelevant unless its 1980.

 I think its the correct way around. You can't accidentally 
 cause memory safety issues. You must explicitly opt-into the 
 ability to mess up your programs state.
I think "safe" BS is going too far. Normally you don't use global variables at all but if you do the most usual is to use normal global variables with perhaps some kind of synchronization primitive. TLS is quite unusual and having TLS by default might even introduce bugs as the programmer believes that the value can be set by all threads while they are independent. Regardless, __gshared in front of the variable isn't a huge deal but it shows that the memory model in D is a leaking bucket. Some compilers enforce synchronization primitives for global variables and are "safe" that way. However, sometimes you don't need them like in small systems that only has one thread and it just gets in the way. TLS by default is mistake in my opinion and it doesn't really help. TLS should be discouraged as much as possible as it is complicated and slows down thread creation.
Apr 01 2023
prev sibling parent reply IGotD- <nise nise.com> writes:
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 Having TLS by default is actually quite desirable if you like 
 your code to be safe without having to do anything extra.

 As soon as you go into global to the process memory, you are 
 responsible for synchronization. Ensuring that the state is 
 what you want it to be.

 Keep in mind that threads didn't exist when C was created. They 
 could not change their approach without breaking everyone's 
 code. So what they do is totally irrelevant unless its 1980.

 I think its the correct way around. You can't accidentally 
 cause memory safety issues. You must explicitly opt-into the 
 ability to mess up your programs state.
I think "safe" BS is going too far. Normally you don't use global variables at all but if you do the most usual is to use normal global variables with perhaps some kind of synchronization primitive. TLS is quite unusual and having TLS by default might even introduce bugs as the programmer believes that the value can be set by all threads while they are independent. Regardless, __gshared in front of the variable isn't a huge deal but it shows that the memory model in D is a leaking bucket. Some compilers enforce synchronization primitives for global variables and are "safe" that way. However, sometimes you don't need them like in small systems that only has one thread and it just gets in the way. TLS by default is mistake in my opinion and it doesn't really help. TLS should be discouraged as much as possible as it is complicated and slows down thread creation.
Apr 01 2023
parent Guillaume Piolat <first.last spam.org> writes:
On Saturday, 1 April 2023 at 08:47:54 UTC, IGotD- wrote:
 TLS by default is mistake in my opinion and it doesn't really 
 help. TLS should be discouraged as much as possible as it is 
 complicated and slows down thread creation.
It looks like a mistake if we consider none of the D-inspired languages have stolen TLS-by-default.
Apr 01 2023
prev sibling next sibling parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 What i find even more weird is writing fast code is ugly in D

 Look at this ugly code

 ```D
 __gshared int fast_code_ugly;
 ```
Because it should be rare that __gshared is used. And if you need it, you won't be worried about how the storage class looks because you'll be concentrating on if your design is thread-safe.
 It should be the opposite
Then by default, safe code can not access global variables and there can easily be accidental races between threads.
Mar 26 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Sunday, 26 March 2023 at 18:29:17 UTC, Nick Treleaven wrote:
 On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 What i find even more weird is writing fast code is ugly in D

 Look at this ugly code

 ```D
 __gshared int fast_code_ugly;
 ```
Because it should be rare that __gshared is used. And if you need it, you won't be worried about how the storage class looks because you'll be concentrating on if your design is thread-safe.
I don't understand this argument, if my code doesn't do threads, why should i put my variable into TLS? If i want fast code, why should i make use of ugly syntax?
Mar 26 2023
next sibling parent Nick Treleaven <nick geany.org> writes:
On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:
 if my code doesn't do threads, why should i put my variable 
 into TLS?
I don't think writing __gshared is a huge burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good option for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.
 If i want fast code, why should i make use of ugly syntax?
By default D supports threads and accidental data races are far worse than ugly syntax.
Mar 31 2023
prev sibling parent reply Nick Treleaven <nick geany.org> writes:
On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:
 if my code doesn't do threads, why should i put my variable 
 into TLS?
I don't think writing __gshared is much of a burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good enhancement for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.
 If i want fast code, why should i make use of ugly syntax?
1. If you want fast code, why aren't you using threads? 2. By default D supports threads and accidental data races are far worse than ugly syntax.
Mar 31 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Friday, 31 March 2023 at 10:26:32 UTC, Nick Treleaven wrote:
 On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:
 if my code doesn't do threads, why should i put my variable 
 into TLS?
I don't think writing __gshared is much of a burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good enhancement for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.
 If i want fast code, why should i make use of ugly syntax?
1. If you want fast code, why aren't you using threads? 2. By default D supports threads and accidental data races are far worse than ugly syntax.
It is a burden to type things you don't need, and to type things that are ugly on purpose I recently discovered -vtls and indeed is very nice to have, managed to clear out all my TLS usage, but made my code even more ugly ``__gshared`` everywhere..
 If you want fast code, why aren't you using threads?
threads is not synonymous of fast code and if i were to use thread, i'd not rely on globals to begin with
 By default D supports threads and accidental data races are far 
 worse than ugly syntax.
Debatable, but that's a good point, but that's not the point i bring, the point i bring is ``__gshared`` is ugly, so we want an ugly language?
Mar 31 2023
parent reply Dennis <dkorpel gmail.com> writes:
On Friday, 31 March 2023 at 15:52:21 UTC, ryuukk_ wrote:
 the point i bring is ``__gshared`` is ugly, so we want an ugly 
 language?
Good code shouldn't look ugly, but global mutable variables are bad, so it's appropriate that they look ugly. You can still put a single `__gshared:` at the top of your module.
Mar 31 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Friday, 31 March 2023 at 16:02:35 UTC, Dennis wrote:
 On Friday, 31 March 2023 at 15:52:21 UTC, ryuukk_ wrote:
 the point i bring is ``__gshared`` is ugly, so we want an ugly 
 language?
Good code shouldn't look ugly, but global mutable variables are bad, so it's appropriate that they look ugly. You can still put a single `__gshared:` at the top of your module.
I disagree, global mutables are not bad That the same bad advice as telling people to "embrace OOP and multiple inheritance" and all the Java BS "just put your variable into a class and make it static, and then have your singleton to access your static variables"
Mar 31 2023
next sibling parent Dennis <dkorpel gmail.com> writes:
On Friday, 31 March 2023 at 16:26:36 UTC, ryuukk_ wrote:
 That the same bad advice as telling people to "embrace OOP and 
 multiple inheritance" and all the Java BS

 "just put your variable into a class and make it static, and 
 then have your singleton to access your static variables"
I agree that singletons aren't any better than global variables. The better way is to pass state through function parameters.
Mar 31 2023
prev sibling parent reply bachmeier <no spam.net> writes:
On Friday, 31 March 2023 at 16:26:36 UTC, ryuukk_ wrote:

 I disagree, global mutables are not bad

 That the same bad advice as telling people to "embrace OOP and 
 multiple inheritance" and all the Java BS

 "just put your variable into a class and make it static, and 
 then have your singleton to access your static variables"
Those of us that have been scarred by reading FORTRAN 77 code would disagree. I use global mutables myself (and even the occasional goto), but if anything, it should be `__GLOBAL_MUTABLE_VARIABLE` to increase the pain of using them.
Mar 31 2023
parent reply Guillaume Piolat <first.last spam.org> writes:
On Friday, 31 March 2023 at 19:43:42 UTC, bachmeier wrote:
 Those of us that have been scarred by reading FORTRAN 77 code 
 would disagree. I use global mutables myself (and even the 
 occasional goto), but if anything, it should be 
 `__GLOBAL_MUTABLE_VARIABLE` to increase the pain of using them.
But you kind of get into the same things with "accidental TLS". It doesn't race, but now the variable is different for every thread, which is a different kind of race. TLS could be explicit and we wouldn't need a -vtls flag. There is no flag to warn for every use of trusted, so in the grand scheme of things TLS is more dangerous than trusted.
Apr 01 2023
parent Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 1 April 2023 at 13:11:46 UTC, Guillaume Piolat wrote:
 TLS could be explicit and we wouldn't need a -vtls flag.
Yeah, I think what we should do is make each thing be explicitly marked. When I want tls, I tend to comment that it was intentional anyway to make it clear I didn't just forget to put a shared note on the static.
Apr 01 2023
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/26/23 2:07 PM, ryuukk_ wrote:
 Hi,
 
 It's common knowledge that accessing tls global is slow 
 http://david-grs.github.io/tls_performance_overhead_cost_linux/
 
 What i do not understand is the reasoning behind choosing tls global by 
 default in D
If you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data". -Steve
Mar 26 2023
parent reply ryuukk_ <ryuukk.dev gmail.com> writes:
On Sunday, 26 March 2023 at 19:08:32 UTC, Steven Schveighoffer 
wrote:
 On 3/26/23 2:07 PM, ryuukk_ wrote:
 Hi,
 
 It's common knowledge that accessing tls global is slow 
 http://david-grs.github.io/tls_performance_overhead_cost_linux/
 
 What i do not understand is the reasoning behind choosing tls 
 global by default in D
If you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data". -Steve
I haven't explored this use case, that must explain why i find it surprising, however, i read about other languages too, and they seem to be explicit whenever they make use of TLS C, C++, Rust, Zig, Go doesn't do TLS by default for example
Mar 26 2023
next sibling parent z <z z.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 ``shared`` is even more ugly since everything must be shared 
 afterwards
The limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/26/23 4:41 PM, ryuukk_ wrote:
 On Sunday, 26 March 2023 at 19:08:32 UTC, Steven Schveighoffer wrote:
 On 3/26/23 2:07 PM, ryuukk_ wrote:
 Hi,

 It's common knowledge that accessing tls global is slow 
 http://david-grs.github.io/tls_performance_overhead_cost_linux/

 What i do not understand is the reasoning behind choosing tls global 
 by default in D
If you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data".
I haven't explored this use case, that must explain why i find it surprising, however, i read about other languages too, and they seem to be explicit whenever they make use of TLS C, C++, Rust, Zig, Go doesn't do TLS by default for example
If you want to have the type system tell you when a variable is readable from other threads or not, you need to have *something* to distinguish them. 99% of all variables are not readable from other threads, so making that the default seems the right call to me. I don't know if you have thought through the implications. Start with the requirement that I need to know by examining the type whether the value is viewable from multiple threads. Is there a better mechanism with better defaults? C/C++ is precisely the wrong answer -- just let the programmer fend for himself. I haven't used the others to know what their story is. One possibility is to REQUIRE you to mark module-level and static variables as one of `__gshared`, `shared`, `immutable`, or ` tls`. I would be OK with such a change. I've run into a situation where I want to make a thread local pointer to shared data, and it's not easy. The only solution I could come up with is to put it inside a dummy struct with a shared member. Having a ` tls` storage class would help solve that. -Steve
Mar 27 2023
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/26/23 13:41, ryuukk_ wrote:

 C, C++, Rust, Zig, Go doesn't do TLS by default for example
C doesn't do because there was no such concept when it was conceived. C++ doesn't do because they built on top of C. (D does because it has always been innovative.) Go doesn't do because it had no innovations anyway. Does anyone have documentation on why Rust and Zip does not do thread local by default? I wonder what experience it was based on. Speaking of experience, I used to be a C++ programmer. We made use of thread-local storage precisely zero times. I think it's because the luminaries of the time did not even talk about it. With D, I take good advantage of thread-local storage. Interestingly, I do that *only* for fast code. void foo(int arg) { static int[] workArea; if (workArea.length < nededFor(arg)) { // increase length } // Use workArea } Now I can use any number of threads using foo and they will have their independent work areas. Work area grows in amortized fashion for each thread. I find the code above to be clean and beautiful. It is very fast because there are no synchronization primitives needed because no work area is shared between threads. Finding one example to the contrary does not make TLS a bad idea. Engineering is full of compromises. I agree with D's TLS by-default idea. Since I am here, I want to touch on something that may give the wrong idea to newer D programmers: D does not have globals. Every symbol belongs to a module. And copying an earlier comment of yours:
 It's common knowledge that accessing tls global is slow
 http://david-grs.github.io/tls_performance_overhead_cost_linux/
"TLS global is slow" would be misleading because even the article you linked explains right at the top, in the TL;DR are that "TLS may be slow". Ali
Apr 01 2023
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 4/1/23 17:02, Ali Çehreli wrote:
 
 Does anyone have documentation on why Rust and Zip does not do thread 
 local by default?
Rust just does not do mutable globals except in unsafe code.
Apr 01 2023
prev sibling parent IGotD- <nise nise.com> writes:
On Saturday, 1 April 2023 at 15:02:12 UTC, Ali Çehreli wrote:
 Does anyone have documentation on why Rust and Zip does not do 
 thread local by default? I wonder what experience it was based 
 on.
I think that would hard to get documentation on the rationale for that decision. Maybe you can get an answer in their forums but I doubt it. For Rust I think they based it on that globals should have some kind of synchronization which is enforced at compile time. Therefore TLS becomes second citizen.
 Speaking of experience, I used to be a C++ programmer. We made 
 use of thread-local storage precisely zero times. I think it's 
 because the luminaries of the time did not even talk about it.
Yes, that's "normal" programming that you more or less never use TLS.
 With D, I take good advantage of thread-local storage. 
 Interestingly, I do that *only* for fast code.

 void foo(int arg) {
     static int[] workArea;

     if (workArea.length < nededFor(arg)) {
         // increase length
     }

     // Use workArea
 }

 Now I can use any number of threads using foo and they will 
 have their independent work areas. Work area grows in amortized 
 fashion for each thread.

 I find the code above to be clean and beautiful. It is very 
 fast because there are no synchronization primitives needed 
 because no work area is shared between threads.
There is nothing beautiful with it other than the clean syntax. Why not just use a stack variable which is thread local as well. TLS is often allocated on the stack in many systems anyway. Accessing TLS variables can slower compared to stack variables. The complexity of TLS doesn't pay for its usefulness.
 It's common knowledge that accessing tls global is slow
 
http://david-grs.github.io/tls_performance_overhead_cost_linux/ "TLS global is slow" would be misleading because even the article you linked explains right at the top, in the TL;DR are that "TLS may be slow".
This depends how it is implemented. TLS is really a forest and can be implemented in many ways and it also depends where it is being accessed (shared libraries, executable etc.). In general TLS on x86 is accessed by fs:[-offset_to_variable] this isn't that slow but the complexity to get there is high. Keep in mind the TLS area must be initialized for every thread creation which isn't ideal. fs:[] isn't always possible and a function call is required similar to a DLL symbol look up. TLS is a turd which shouldn't have been created. They should have stopped with key/value pair which languages then could build on if they wanted. Now TLS are in the executable standards and it is a mess. x86 has now two ways of TLS (normal and TLS_DESC) just to make things even more complicated. A programmer never see this mess but as systems programmer I see this and it is horrible.
Apr 01 2023
prev sibling next sibling parent z <z z.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:

 ``shared`` is even more ugly since everything must be shared 
 afterwards
The limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
prev sibling next sibling parent reply wjoe <invalid example.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 It should be the opposite

 Slow code ugly
 Fast code beautiful
What's fast today may not be fast tomorrow but the language might still be relevant. e.g.: It used to be faster to ... - pre-calculate sin/cos tables, now the memory look up cost more cycles than the calculation itself - use fixed point integer math, now every CPU has what used to be a floating point co-processor integrated - only redraw the parts of the screen that changed, now the branching is slower than to redraw everything another example is sorting - Alexei wrote a blog post about how a stupid and slow sorting algorithm now performs better in multi threading. Maybe someone remembers the title/url of the post ? And finally, beauty is in the eye of the beholder - meaning it's purely subjective.
Mar 27 2023
parent Nick Treleaven <nick geany.org> writes:
On Monday, 27 March 2023 at 08:44:41 UTC, wjoe wrote:
 e.g.: It used to be faster to ...

 - pre-calculate sin/cos tables, now the memory look up cost 
 more cycles than the calculation itself
...
 - only redraw the parts of the screen that changed, now the 
 branching is slower than to  redraw everything
Good to know, thanks.
 another example is sorting - Alexei wrote a blog post about how 
 a stupid and slow sorting algorithm now performs better in 
 multi threading. Maybe someone remembers the title/url of the 
 post ?
Not sure, but that reminds me of Andrei's blog on partitioning (for quicksort): https://dlang.org/blog/2020/05/14/lomutos-comeback/ The algorithm traditionally considered slower can be faster because it can be optimized to work better with branch prediction.
Mar 31 2023
prev sibling next sibling parent z <z z.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:

 ``shared`` is even more ugly since everything must be shared 
 afterwards
The limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
prev sibling next sibling parent z <z z.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 ``shared`` is even more ugly since everything must be shared 
 afterwards
The limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
prev sibling next sibling parent Jacob Shtokolov <jacob.100205 gmail.com> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 What i do not understand is the reasoning behind choosing tls 
 global by default in D
Because the language maintainers decided that they want to emphasize the actor model with no default shared state in the language. This is quite beneficial, BTW, as multiprocessor programming is by no means an easy problem, so the language just pushes you towards the error-free code by default. As for `__gshared`, this is intended only for interfacing with C and other languages where global variables is the default way of doing things. This may seem ugly, but if you write your program completely in D and want to avoid TLS, why don't you avoid globals at all? Just allocate some state on the stack and pass it to your functions as `ref`. This way it will actually be much cleaner and easy to understand and test, because global variables are tempting to be mutated, which makes the program control flow much less transparent.
Mar 27 2023
prev sibling parent Guillaume Piolat <first.last spam.org> writes:
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:
 Even C does it better: 
 https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html
Honestly I find TLS-by-default to be a bad idea, it has become a trap to be avoided, and TLS does occasionally speed up things but it should be opt-in.
Mar 27 2023