Tuesday, January 22, 2019

Digest for comp.lang.c++@googlegroups.com - 25 updates in 4 topics

anhongleetcode@gmail.com: Jan 21 08:59PM -0800

Hi experts,
 
I am new to C++, I would like to have a buffer using std::vector, like
 
```cpp
std::vector<char> buf;
 
buf.resize(64 * 1024 * 1024 * 1024);
fread(buf.data(), buf.size(), 1, fp);
 
func(buf.data()); // consuming it
 
```
 
I like vector, but the resize will initialize the whole vector as zero.
Which is unwanted, I don't even need it, it's a waste!
 
How could I skip this?
Some people warned me the following code is dangerous...
Because assessing data() outside of range [data, data + size) is undefined:
 
 
```cpp
std::vector<char> buf;
 
buf.reserve(64 * 1024 * 1024 * 1024);
fread(buf.data(), buf.size(), 1, fp);
 
func(buf.data()); // consuming it
 
```
 
then what's the proper/elegant way?
I need pretty big buffer so I have to dynamically allocate it.
 
 
Thanks,
Anhong
Daniel <danielaparker@gmail.com>: Jan 21 09:27PM -0800


> I like vector, but the resize will initialize the whole vector as zero.
> Which is unwanted, I don't even need it, it's a waste!
 
> How could I skip this?
 
Some alternatives:
 
http://andreoffringa.org/?q=uvector
 
Personally, I wouldn't worry about it.
 
Daniel
Barry Schwarz <schwarzb@dqel.com>: Jan 21 10:30PM -0800

On Mon, 21 Jan 2019 20:59:52 -0800 (PST), anhongleetcode@gmail.com
wrote:
 
>std::vector<char> buf;
 
>buf.resize(64 * 1024 * 1024 * 1024);
>fread(buf.data(), buf.size(), 1, fp);
 
Your call to fread specifies a single object 64GB in size. How will
you know exactly how much data was actually read in?
 
Just out of curiosity, how long will it take your system to read a
64GB block?
 
 
>How could I skip this?
>Some people warned me the following code is dangerous...
>Because assessing data() outside of range [data, data + size) is undefined:
 
It's no more dangerous than any other indexing operation. fread will
certainly not access memory beyond the end of the array. It is up to
you to make sure that func won't either.
 
--
Remove del for email
Jorgen Grahn <grahn+nntp@snipabacken.se>: Jan 22 06:44AM

> fread(buf.data(), buf.size(), 1, fp);
 
> func(buf.data()); // consuming it
 
> ```
 
Is this your actual use case -- to read a 64 gigabyte file into memory
in one big chunk, then process the data?
 
> I like vector, but the resize will initialize the whole vector as zero.
> Which is unwanted, I don't even need it, it's a waste!
 
I can see why you don't want it in this particular case, but normally
it's a very good thing: std::vector<T> should help protect the invariant
of T.
 
If you want the huge file in memory as-is, one alternative is mmap().
It's a Unix function, but Windows has something similar and I suspect
Boost has a portable API for it.
 
Another option is to read the file in smaller chunks and process the
data as it arrives, discarding it when you don't need it anymore. But
that may not be possible depending on the file format and the task.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Paavo Helde <myfirstname@osa.pri.ee>: Jan 22 09:23AM +0200


> buf.resize(64 * 1024 * 1024 * 1024);
> fread(buf.data(), buf.size(), 1, fp);
 
> func(buf.data()); // consuming it
 
Wow, 64 GB? If this is really a case, you should use memory mapping
instead of reading it in in one go (but memory mapping is non-standard
and has its own caveats).
 
> ```
 
> I like vector, but the resize will initialize the whole vector as zero.
> Which is unwanted, I don't even need it, it's a waste!
 
Programming is an engineering disciple, which means you have to be
pragmatic. As the file reading will most probably be several orders of
magnitudes slower than the memory zeroing, it is a safe bet one can just
ignore the time spent on zeroing in this scenario. Of course you can
measure the timings first and then decide if this is something to spend
time on or not.
 
> How could I skip this?
 
Buffer zeroing may cause significant overhead in other scenarios (not
related to file reading). I ended up with making my own small wrapper
class wrapping (the equivalent of) malloc() directly. But I did this
only after repeated performance profiling had convinced me that one
could win more than 10% this way, and there seemed to be no other way to
squeeze the performance.
 
TLDR; first profile your program and then decide which parts of it need
speeding up.
Juha Nieminen <nospam@thanks.invalid>: Jan 22 08:12AM

> I like vector, but the resize will initialize the whole vector as zero.
> Which is unwanted, I don't even need it, it's a waste!
 
As others have pointed out, in your particular scenario allocating a 64GB
block of memory might not be really what you want (mmap is usually what's
used to handle huge raw files as efficiently as possible, even though it's
not a standard function). But anyway, to answer your actual question:
 
std::vector isn't really designed to manage uninitalized memory, and this
is by design.
 
Perhaps the easiest way to get a block of uninitalized memory, C++ style,
is this:
 
std::unique_ptr<unsigned char[]> data
((unsigned char*)::operator new[](1234));
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
David Brown <david.brown@hesbynett.no>: Jan 22 09:36AM +0100

On 22/01/2019 07:30, Barry Schwarz wrote:
> you know exactly how much data was actually read in?
 
> Just out of curiosity, how long will it take your system to read a
> 64GB block?
 
My guess is that the OP is looking at this as an easy way to read in the
whole file as simply as possible. Allocate a memory chunk that is
bigger than any file he might want, but don't access that memory so that
it is left unmapped (on many systems). Read the file into the buffer -
no need to worry about buffer overrun with such a large buffer, and
fread a larger size than any file might be. That way you are sure
you've got everything in the file, with just a few lines of code. No
need to read in chunks, or move or copy memory around.
 
This is, of course, a /highly/ questionable approach in many ways. So
my advice is for the OP to take a step back and look at what he wants to
achieve - ask about that, rather than details of an attempted
implementation. mmap() is probably a better answer, but that might
depend on the OS, the types of file, etc.
 
Or question the choice of C++ in the first place, especially if you are
new to the language - make sure you use the right language for the job.
In Python, this is:

data = file("xxx.dat").read()
 
 
But if you /really/ want to get a buffer of 64 GB space without touching
any of it, use malloc(), not a C++ container. Just wrap it in an RAII
class to be sure it is freed.
Paavo Helde <myfirstname@osa.pri.ee>: Jan 22 10:46AM +0200

On 22.01.2019 9:23, Paavo Helde wrote:
 
>> ```cpp
>> std::vector<char> buf;
 
>> buf.resize(64 * 1024 * 1024 * 1024);
 
Side remark: as written, this line is UB because of signed integer
overflow, on most (all?) platforms.
leigh.v.johnston@googlemail.com: Jan 22 01:27AM -0800


> I like vector, but the resize will initialize the whole vector as zero.
> Which is unwanted, I don't even need it, it's a waste!
 
> How could I skip this?
 
Simply use a dynamic array instead:
 
char* buf = new char[64 * 1024 * 1024 * 1024];
 
Allocating uninitialised buffers (including allocating space for placement new) are about the only use-cases for dynamic arrays these days.
 
/Leigh
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jan 22 11:10AM +0100

On 22.01.2019 09:46, Paavo Helde wrote:
 
>>> buf.resize(64 * 1024 * 1024 * 1024);
 
> Side remark: as written, this line is UB because of signed integer
> overflow, on most (all?) platforms.
 
Platforms with 64-bit `int` include the HAL Computer Systems port of
Solaris to the SPARC64 and Classic UNICOS, according to Wikipedia's
article on the issue.
 
 
Cheers!,
 
- Alf
"Öö Tiib" <ootiib@hot.ee>: Jan 22 02:19AM -0800


> ```cpp
> std::vector<char> buf;
 
> buf.reserve(64 * 1024 * 1024 * 1024);
 
That is buf.reserve(0); with gcc 8.1.0 also following warning:
warning: integer overflow in expression of type 'int' results in '0' [-Woverflow]
 
 
 
> ```
 
> then what's the proper/elegant way?
> I need pretty big buffer so I have to dynamically allocate it.
 
Elegant way is to make code that compiles and runs and does
what you actually want it to do then post it here as whole.
It does not matter how fast our customers get incorrect results.
 
Let's look at performance.
DRAM is typically about order of magnitude faster than SSD
so bottle-neck in your posted code is reading the file not
zeroing memory. Even if you buy very decent SSD then freading
64 GB will take over 20 seconds no matter if the buffer
was initialized or not. If you wan't better performance then
you should make your algorithm less naive and to make it
to work with sub-sets of whole data and to load it on need
basis. Full HD video is about 3 GB/hour.
fir <profesor.fir@gmail.com>: Jan 22 02:23AM -0800

W dniu wtorek, 22 stycznia 2019 08:23:23 UTC+1 użytkownik Paavo Helde napisał:
> As the file reading will most probably be several orders of
> magnitudes slower than the memory zeroing,
 
on good pc zeroing 64GB should take 6 seconds (in one core, if you use 6 maybe
it could take 1 second - if they hae independand bandwidth, probably yes)
 
reading from disk: some write good SSD hae 500 GB/s but i never tested it and i belive it may be not exact (to high) but lets take it then - 2 minutes
"Öö Tiib" <ootiib@hot.ee>: Jan 22 02:23AM -0800

On Tuesday, 22 January 2019 12:10:15 UTC+2, Alf P. Steinbach wrote:
 
> Platforms with 64-bit `int` include the HAL Computer Systems port of
> Solaris to the SPARC64 and Classic UNICOS, according to Wikipedia's
> article on the issue.
 
Yes, but Anhong won't get anywhere near one of such platforms
anytime soon.
"Öö Tiib" <ootiib@hot.ee>: Jan 22 02:25AM -0800

On Tuesday, 22 January 2019 12:10:15 UTC+2, Alf P. Steinbach wrote:
 
> Platforms with 64-bit `int` include the HAL Computer Systems port of
> Solaris to the SPARC64 and Classic UNICOS, according to Wikipedia's
> article on the issue.
 
Yes, but Anhong won't get anywhere near one of such platforms
anytime soon.
Bonita Montero <Bonita.Montero@gmail.com>: Jan 22 11:28AM +0100

> Wow, 64 GB? If this is really a case, you should use memory mapping
> instead of reading it in in one go (but memory mapping is non-standard
> and has its own caveats).
 
Memory-mapping is slower and / or (depending on the platform) consumes
more cpu-resources because there is usually no prefetching an faults on
every page (thus the higher cpu-overhead).
 
> Buffer zeroing may cause significant overhead in other scenarios (not
> related to file reading).
 
Is a buffer of std::byte really zeroed? I think std::vector simply calls
the default-constructor, which does nothing for std::byte and thereby
the whole internal initialization loop when enlarging the vector shoud
be optimized away.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jan 22 11:28AM +0100

On 22.01.2019 09:12, Juha Nieminen wrote:
> is this:
 
> std::unique_ptr<unsigned char[]> data
> ((unsigned char*)::operator new[](1234));
 
I would not do that, because `std::unique_ptr` for an array effectively
uses an ordinary `delete[]`-expression to deallocate, while the above
requires a direct call of `::operator delete[]`.
 
There is a difference: a `new[]`-expression may ask `operator new[]` for
more than the size of the array, in order to store a count of objects
(so that destructors can be called on the appropriate number of items),
and the `delete[]` expression that `unique_ptr` uses by default, takes
that into account, i.e. it may perform a pointer adjustment. As I recall
it's unspecified whether this happens for an array of POD type. And then
it /can/ happen, i.e. the code wouldn't be portable.
 
A simple remedy is to just use an ordinary `new[]`-expression, or
`make_unique`.
 
 
Cheers!,
 
- Alf
fir <profesor.fir@gmail.com>: Jan 22 02:30AM -0800

W dniu wtorek, 22 stycznia 2019 11:19:22 UTC+1 użytkownik Öö Tiib napisał:
> you should make your algorithm less naive and to make it
> to work with sub-sets of whole data and to load it on need
> basis. Full HD video is about 3 GB/hour.
 
3GB/s SSD ?
"Öö Tiib" <ootiib@hot.ee>: Jan 22 02:36AM -0800

On Tuesday, 22 January 2019 12:28:32 UTC+2, Bonita Montero wrote:
> the default-constructor, which does nothing for std::byte and thereby
> the whole internal initialization loop when enlarging the vector shoud
> be optimized away.
 
No vector::resize must value-initialize the buffer if value wasn't provided.
With char it means zeroes.
"Öö Tiib" <ootiib@hot.ee>: Jan 22 02:41AM -0800

On Tuesday, 22 January 2019 12:30:47 UTC+2, fir wrote:
> > to work with sub-sets of whole data and to load it on need
> > basis. Full HD video is about 3 GB/hour.
 
> 3GB/s SSD ?
 
Yes. 64/3 > 20
Bonita Montero <Bonita.Montero@gmail.com>: Jan 22 11:46AM +0100

>> be optimized away.
 
> No vector::resize must value-initialize the buffer if value wasn't provided.
> With char it means zeroes.
 
The container doesnt know anything about zeroes; it calls the
default-constructor, which is a NOP in case of std::byte.
fir <profesor.fir@gmail.com>: Jan 22 02:54AM -0800

W dniu wtorek, 22 stycznia 2019 11:42:00 UTC+1 użytkownik Öö Tiib napisał:
> > > basis. Full HD video is about 3 GB/hour.
 
> > 3GB/s SSD ?
 
> Yes. 64/3 > 20
 
but where you seen that fast ones?
i not checked like some 2 years but it used to be 500 MB/s
fir <profesor.fir@gmail.com>: Jan 22 03:00AM -0800

W dniu wtorek, 22 stycznia 2019 11:54:53 UTC+1 użytkownik fir napisał:
 
> > Yes. 64/3 > 20
 
> but where you seen that fast ones?
> i not checked like some 2 years but it used to be 500 MB/s
 
ok indeed i found some
 
https://www.techradar.com/reviews/wd-black-sn750-nvme-ssd
 
interesting also is how much speed drop down on non-sequential highly random read (0.5MB its disaster)
"Öö Tiib" <ootiib@hot.ee>: Jan 22 01:18AM -0800

On Monday, 21 January 2019 23:18:51 UTC+2, Jorgen Grahn wrote:
> management[0] and hadn't wrapped it properly. But often you also want
> to run dynamic checkers on others' code to find out how ill-behaved it
> is; then leak checking is a useful feature IMO.
 
Yes, sometimes libraries contain defects, also standard libraries, also
leaks. So always support exact versions of dependencies and update
those only for reason and as separate pull request. Again major headache
avoided close to effortlessly.

Leaks result with symptom that memory usage grows over time. Sometimes
the leaks are "logical". For example more objects are put into some global
container than erased from it over time. Such leaks can't be detected with
any tool. On worst cases it can be quite challenging to figure it out.
 
 
> Address, leak and undefined, then. I see -fsanitize=thread too.
 
> The GCC manual says some of the sanitizers cannot be used together,
> but doesn't say which ones.
 
If you have continuous integration then there are no much difference if
it runs tests 2 times or 10 times (with different compilers and combinations
of instrumentation). Computing power is dirt cheap so people waste it on
total trash (like bitcoins). So I quite strongly suggest to do that. Little
benefits add up into greater perceived quality at low cost.

> > These will typically detect if code misuses operators of containers
> > or iterators; ASan will detect if code misuses pointer arithmetics.
 
> Thanks; I (and others) tend to forget that option.
 
Yes, the assertions of library are way easier to comprehend than same
issue raised by ASan for example. Library asserts first so these can
be used as combination, too.
Josef Moellers <josef.moellers@invalid.invalid>: Jan 22 08:42AM +0100

On 21.01.19 17:45, Scott Lurndal wrote:
>> daysSinceModification or fileAgeInDays would be better".
>> (S)He could have made this more clear, though.
 
> struct stat's st_atime, st_ctime, st_mtime seem clear enough to me...
 
???
 
I was referring to page 5.
There the author has a bullet "No lower-case L or upper-case o, ever."
and to the right of this four closely spaced variable/field
declarations, the first of which has a lower-case l.
 
At first glance, I had taken this as a counter-example, as the
lower-case l really resembles the upper-case I.
 
But looking more closely at this page, it really looks like the author
wants to replace the "int d" by one of the four declarations to the
right of the arrow the first one of them declares the variable/field
with the lower-case l!
 
If the author ever reads this: pdf pages are virtually free, so are
PowePoint or Libre Office Presenter slides! Please don't try to cram as
much as possible onto a single page, it confuses more than it helps.
 
Josef
ram@zedat.fu-berlin.de (Stefan Ram): Jan 22 06:15AM

>I like vector, but the resize will initialize the whole vector as zero.
>Which is unwanted, I don't even need it, it's a waste!
 
Maybe you could use a
 
#include <vector>
#include <cstddef>
 
..
 
::std::vector< buffer_byte >v( buffer_size );
 
with
 
struct buffer_byte { buffer_byte(){} ::std::byte x; };
 
? The constructor will be called for each buffer_byte, but
it will not do anything. Also make sure buffer_size fits
into ::std::vector::size_type.
 
if( !v.empty() )
{ byte * beg = &v.front().value;
byte * end = beg + v.size(); ~~~ }
 
. Other possibilities include: Using a vector with a custom
allocator whose "construct" does nothing.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: