hkaiser changed the topic of #ste||ar to: STE||AR: Systems Technology, Emergent Parallelism, and Algorithm Research | stellar.cct.lsu.edu | HPX: A cure for performance impaired parallel applications | github.com/STEllAR-GROUP/hpx | Buildbot: http://rostam.cct.lsu.edu/ | Log: http://irclog.cct.lsu.edu/
K-ballo has quit [Quit: K-ballo]
hkaiser has quit [Quit: bye]
<lsl88>
Hi! Sorry for the time of the day. Am I on the right track if I finish reading the manual, try to see things that could be improved - ie tables that are difficult to follow, more information that should be added to fully understand one chapter and so on- and afterwards read the examples?
<simbergm>
lsl88: yep, that sounds great
<simbergm>
remember that we're not expecting you to fix the whole manual, but of course the more you read the better your overview of the current state will be, so what you're doing is much appreciated
Amy1 has quit [Ping timeout: 258 seconds]
Amy1 has joined #ste||ar
nikunj has joined #ste||ar
lsl88 has quit [Ping timeout: 245 seconds]
Coldblackice has quit [Ping timeout: 268 seconds]
<Yorlik>
I just started to eliminate C style casts from my allocators and replace them with C++ style casts. I am ending up with some really ugly code though, like:
<Yorlik>
Any hints for getting the best of both worlds, like pointer arithmetic and low level void* spammage but also as much type safety as possibnle?
<Yorlik>
I tried to find some good sources for learning and ended up with the C++ guidelines - I wonder if there are any good tutorial resources for this area of work.
hkaiser has joined #ste||ar
<Yorlik>
Heyo hkaiser! If you read up a couple of lines .. would you pls answer some newbie issue with pointer arithmetic coding style? (C vs C++ casts)?
<hkaiser>
uhh
<hkaiser>
I don't know anything about pointers ;-)
<Yorlik>
You'r joking, right? Or do you imply you never ever use pointer again?
<hkaiser>
you want to have type safety but at the same moment you use reinterpret_cast
<hkaiser>
that does not go together
<hkaiser>
but seriously
<Yorlik>
I wonder if I should create new types
<hkaiser>
you don't need to cast a pointer first to uint64 and then to void*
<hkaiser>
a simple static_cast<void*>(ptr) will do that
<Yorlik>
I want to add an error code to it
<hkaiser>
casting back requires a reinterpret_cast, however
<Yorlik>
The pointer has 12 free bits at the bottom
<hkaiser>
urgs
<Yorlik>
So i want to use it as a tagged pointer to a memory page
<hkaiser>
stick with whatever you had with C-style casts, the C++ version will not give you anything more
<Yorlik>
It might just raise an alarm flag if I see C style casts in my code and avoid them elsewhere
<hkaiser>
you can also create a special type that acts as the tagged pointer
<Yorlik>
I wonder if a special class with static functions for tagging could do the trick, so i would encapsulate away the unsafe parts of the code
<Yorlik>
That shouldn't cause any serious runtime issues in terms of performance / memory usage
<Yorlik>
I mean - the code works already - I just got a ton of squiggles and I try to avoid pragma warning away everything
<Yorlik>
cpmressed_ptr_type - lol
<Yorlik>
I like the name already and the underlying type
<zao>
Yorlik: standards-wise you should only cast between regular pointer types and integer types that are of the same size, and not rely on the integer value except that it can roundtrip ptr to int to ptr.
<zao>
uintptr_t is such a suitably sized type.
<Yorlik>
Yeah - my code kinda assumes 64 bit machines
<Yorlik>
But what once we get 128 bit machines ... :D
<Yorlik>
Or we try to run HPX on a Z80 ...
<Yorlik>
But seriously: i really wann write safe code and avoid making it ugly
<zao>
There are 64-bit machines with trap representations for example. All I’m saying is that you’re skirting toward UB territory.
<Yorlik>
What's a trap representation?
<hkaiser>
Yorlik: use size_t instead of uitn64_t, that is guaranteed to be large enough to store a pointer
<hkaiser>
also, the compressed_ptr is probably all you need
<hkaiser>
hides all ugliness
<Yorlik>
I'll study it
<zao>
size_t is technically supposed to only be able to hold the size of an array, which on _most_ architectures is the right size :P
<hkaiser>
zao: you sure?
<zao>
They may have changed the wording around that since 03.
<zao>
Yorlik: You know how floating point numbers can be NaN, and in some CPU modes they cause hardware exceptions?
<Yorlik>
Not really
<Yorlik>
I always kinda assumed NaN would be a special reserved value
<zao>
Special bit patterns that are Not-a-Number, which propagate through numeric operations.
<Yorlik>
But I'm blank on that
<zao>
On some architectures, notably Itanium, there's Not-a-Thing, which holds for regular integers.
<Yorlik>
They are hardware defined?
<Yorlik>
I think I might just make a special MemoryPagePtr class form my purposes as an excercise and taking inspiration from your compressed Ptr
<Yorlik>
And avoid any dynamic / virtual stuff in it
<Yorlik>
Yesterday I ended up teaching catch2 to test against segfaults ... :D
<zao>
I looked them up, seems like NaT:s are not directly part of the value representation, so they're not necessarily a problem here :D
<zao>
I'm sure your code is "fine", it's just the coercion to a type that's not necessarily of pointer size that's iffy.
<zao>
hkaiser: cppreference seems to imply that it only needs to be able to store the maximum size of an object, which could technically be smaller than a pointer.
<Yorlik>
The problem is, that strategically other developers might use my code in the future, write new allocators or poke around in existing code and all this allocation stuff is so deep in the system I really want to make it as rock solid as i can.
<zao>
It's the kind of reading that ##c++ would love to have :P
<zao>
Personally I'm mostly scared of overly clever compilers optimizing my code according to spec.
<Yorlik>
When doing arithmetic on memory cells - is there a c++ type that is guaranteed to always be able represent a single cell? Should I use byte or char?
<Yorlik>
It's more a theoreical question, but after all void* has no type and I need to do arithmetic on memory cells, on pages too etc.
<Yorlik>
So I believe I should represent them propely instead of doinf wild void* casts all over the place
<Yorlik>
Sry - my typing is horrible again - need more coffee ... :)
nikunj has quit [Remote host closed the connection]
<zao>
`unsigned char` has been a good bet in the past as it has unsurprising signedness, haven't done C++ since std::byte appeared.
<Yorlik>
IC - thanks for the link! Seems unsigned char and byte are equivalent. I might just use byte for the lowlevel thing because its more precise imo.
<Yorlik>
With "char" you always think of something that prints.
<Yorlik>
But a byte I can print as char, int or hex
<zao>
Doesn't matter much when you're operating on the pointer type, but char has implementation-defined signedness, which is always fun.
<Yorlik>
BTW - there is another interesting detail in that article: "For example, multiple floating-point bit patterns represent the same special value NaN. "
<Yorlik>
So - not all NaNs are equal internally - didn't know that
<zao>
There's like a million of them.
<Yorlik>
wow
<Yorlik>
I think I'll se them as neglected orphans ...
* Yorlik
feels some wird pity for the NaNs all at a sudden
<zao>
f32 has a 8-bit exponent, where an exponent of 0xFF is all NaNs, 0x00 is all denormals.
<Yorlik>
I'm totally undereducated in this IEEE stuff - first stumbled over it when working with Lua - seems there is some learning to do.
<Yorlik>
I start wondering why would we ever need void*? Any pointer to a memory cell could be byte* - couldn't/shouldn't it?
<hkaiser>
byte* implies a type, void* does not
<zao>
There's some value in a vocabulary type that has some semantic distinctions.
<Yorlik>
You mean because byte* would imply the traget has 1 byte length and void* is totally open to any interpretation?
<hkaiser>
yes
<zao>
byte* also has some alignment assumptions, and sometimes it's great not being able to dereference or do arithmetic.
<Yorlik>
It somehow makes sense to not have pointer arihmetic for void*, still it is a bit awkward to use casts to byte or char to actually do arithmetic with void*. otoh - maybe the problem is the ease of misusing void*.
<hkaiser>
Yorlik: doing pointer arithmetic with (u)char* implies an object size of one (byte)
<Yorlik>
Yes - a single memory cell.
<hkaiser>
instead of foo* p = ... ; ((char*)p) + sizeof(foo) you could write ++p
<Yorlik>
The problem appears at the interface to the OS, which always requires void* to reserve an address space and to commit a page. I think I'll just put the conversion closely there and above use pages or my object types.
<hkaiser>
any pointer is default convertible to void*
<hkaiser>
so you only need to cast when you go from a void* to foo*
<hkaiser>
(well any non-member function pointer, but those are not really 'pointers' anyways)
<Yorlik>
My low level API is like this(different implementations per OS under the hood):