Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Volguus
Mar 3, 2009

Ihmemies posted:

Well, no. I guess I can have many QMainWindows?

Like, the launcher where user can define the game area size, like x,y, set seed etc. is a QMainWindow. Then when user has figured out what kind of game he wants to play, it launches the game_window.

Anyways I made view and scene class variables, and changed the game_window from qwidget to qmainwindow. Then I can use setcentralwidget and it puts something to the screen, finally:

code:
Game_window::Game_window(MainWindow *parent) :
    QMainWindow(parent, Qt::Window)
{
    //parent->hide();
    this->setStyleSheet("background-color: yellow;");

    scene = new QGraphicsScene();
    Game_board* board = new Game_board;
    scene->addItem(board);
    view = new QGraphicsView(scene);
    this->setCentralWidget(view);

    parentWidget()->hide();
}{
It doesn't put what I want to screen, but at least it's somehow doing something.. which is more than before. Thanks!

I mean it displays a tiny window with nothing, but I can close it and move around. Not ideal, yet:



Oh, that's what you want? I suppose you can have multiple QWindow objects. QGraphicsView inherits from QAbstractScrollArea and that's a widget, you can put that anywhere you want. Would maybe a MDI application fit your idea better?

Adbot
ADBOT LOVES YOU

Ihmemies
Oct 6, 2012

I have no idea at all what MDI is. I'm just trying to get this done. I don't think I've ever played a game where options are visible on the same screen as the actual game, they've always been in a separate options menu or something. And preferrably while playing, the option menu is hidden until ESC/F10 is pressed..

I don’t want the game view to be scrollable either. A snake game is nota hex strat game with a big scrollable map either. Well. Maybe I’ll eventually figure out a way to tell the computer what I want done.

Ihmemies fucked around with this message at 08:23 on Nov 29, 2022

Ihmemies
Oct 6, 2012

Well I finally figured out what was missing. The graphics item class constructor was empty, while it actually needed this to the constructor:

code:
setGraphicsItem(this);
Now to figure out how to get rid of that fuckin extra window.. I deeply hate Qt and it's "examples" and "documentation" at this point.

Or maybe it's intended. At least I'm getting some results now finally!

horse_ebookmarklet
Oct 6, 2003

can I play too?
I'm using ffmpeg's libav to realtime take some RGB565 swscale to YUV420P, then encode to a h264 elementary stream. I am going to mux it into a container at some point, but small steps as this is my first dive into ffmpeg

Anyway, I am calling avcodec_send_frame with an increasing frame->pts
When I call and it produces a packet, avcodec_receive_packet, pkt->pts is "out of order"

Is it normal for an h264 elementary stream to have its packets/pts out of order?
In the below example pts goes 1, 3, 2, 5, 4. I think this is making playback in a tool like VLC look crappy

code:
 avcodec_send_frame, m_frame->pts =  1
 avcodec_send_frame, m_frame->pts =  2
 avcodec_send_frame, m_frame->pts =  3
 avcodec_send_frame, m_frame->pts =  4
 avcodec_send_frame, m_frame->pts =  5
 avcodec_send_frame, m_frame->pts =  6
 avcodec_send_frame, m_frame->pts =  7
 avcodec_send_frame, m_frame->pts =  8
 avcodec_send_frame, m_frame->pts =  9
 avcodec_send_frame, m_frame->pts =  10
 avcodec_send_frame, m_frame->pts =  11
 avcodec_receive_packet, m_pkt->pts =  1 , size:  200
 avcodec_send_frame, m_frame->pts =  12
 avcodec_receive_packet, m_pkt->pts =  3 , size:  53
 avcodec_send_frame, m_frame->pts =  13
 avcodec_receive_packet, m_pkt->pts =  2 , size:  51
 avcodec_send_frame, m_frame->pts =  14
 avcodec_receive_packet, m_pkt->pts =  5 , size:  55
 avcodec_send_frame, m_frame->pts =  15
 avcodec_receive_packet, m_pkt->pts =  4 , size:  51

nielsm
Jun 1, 2009



H.264 video with B-frames can store frames out of order in the stream, since a B-frame will need later frames already decoded to be able to decode correctly. Normally the encoder and decoder will handle the reordering on their own and just push/pull frames as appropriate.

horse_ebookmarklet
Oct 6, 2003

can I play too?
Ok, so that is normal and OK.
This could plausibly be VLC not having enough information, since its not in a container and it can't know more frames are coming?
Guess I'll just keep on truckin and get it muxed.
Thanks!

Absurd Alhazred
Mar 27, 2010

by Athanatos

horse_ebookmarklet posted:

Ok, so that is normal and OK.
This could plausibly be VLC not having enough information, since its not in a container and it can't know more frames are coming?
Guess I'll just keep on truckin and get it muxed.
Thanks!

Yeah, you have to have a container. The procedure you're looking for is (video, audio channel 0, audio channel 1, etc) -> container. Video can be a bunch of formats, audio can be a bunch of formats, and then the container will be AVI, MKV, etc, and that tells the player the respective formats, timing and metadata and how to work these things together.

cheetah7071
Oct 20, 2010

honk honk
College Slice
Is the code below insane? I'm self-taught in C++ so I'm not always familiar with the correct patterns to get what I want.

The purpose of this code is to have a class which matches an interface, where if I forget to implement any part of it, the code just won't compile, and where the functions that the rest of the code sees automatically get populated without anything else having to know anything about the new class. This implementation guarantees that adding a new element to my enum will cause a Parameter object templated with that new value to be created and the parts of the code that request that class to do something already know how to access it without any changes.

The ugly part of this code, which makes me suspect that there's a better way, is that I'm using a template that doesn't *do* anything, besides be used as an index in an array (so I guarantee the Nth element of the array is instantiated with the version of the class templated with N). I also have to do the weird recursive function to make that actually work, and have an element of an enum whose only purpose is to be one past the last valid number. I'm also constantly casting enums to ints and back. It's just kind of ugly, and ugly code usually makes me think that I'm doing something wrong.

In this example, the rest of the code only uses the ParamName enum, and the ParamHolder class, which is how they access the parameters they need to do the actual work of the program. The ParamBase and Parameter classes are implementation details.

C++ code:
enum class ParamName {
	ParamOne,
	ParamTwo,

	_Count_NotAParam
};

class ParamBase {
public:
	virtual void FunctionOne() = 0;
	virtual void FunctionTwo() = 0;
};

template<ParamName N>
class Parameter : public ParamBase {};

template<>
class Parameter<ParamName::ParamOne> : public ParamBase {
public:
	void functionOne() override {/*implementation*/}
	void functionTwo() override {/*implementation*/}
};

template<>
class Parameter<ParamName::ParamTwo> : public ParamBase {
public:
	void functionOne() override {/*implementation*/}
	void functionTwo() override {/*implementation*/}
};

class ParamHolder {
public:

	ParamHolder() {
		constexpr ParamName p = (ParamName)0;
		addParam<p>();
	}

	void doAllFunctionOne() {
		for (size_t i = 0; i < params.size(); ++i) {
			params[i]->functionOne();
		}
	}

	void doOneFunctionTwo(ParamName p) {
		params[(int)p]->functionTwo();
	}

private:

	std::vector<std::unique_ptr<ParamBase>> params;

	template<ParamName N>
	void addParam() {
		if constexpr (N == ParamName::_Count_NotAParam) {
			return;
		}
		else {
			params.push_back(std::make_unique<Parameter<N>>());
			constexpr ParamName NEXT = (ParamName)((int)N + 1);
			addParam<NEXT>();
		}
		
	}
};

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

cheetah7071 posted:

The purpose of this code is to have a class which matches an interface, where if I forget to implement any part of it, the code just won't compile, and where the functions that the rest of the code sees automatically get populated without anything else having to know anything about the new class. This implementation guarantees that adding a new element to my enum will cause a Parameter object templated with that new value to be created and the parts of the code that request that class to do something already know how to access it without any changes.
I think what you're probably looking for is the registration pattern, which goes something like this and will let you get rid of the enum and templates, and also will mean you can *really* make the callers need no knowledge of the implementations, and the implementations also need no knowledge of each other's existence.

code:
class ParamBase {
public:
	virtual void FunctionOne() = 0;
	virtual void FunctionTwo() = 0;
};

class ParamOne : public ParamBase {
public:
	void functionOne() override {/*implementation*/}
	void functionTwo() override {/*implementation*/}
        // It is common to use a #define for this.
        static const bool registered_ = ParamHolder::singleton().register(std::make_unique<ParamOne>());
};

class ParamTwo : public ParamBase {
public:
	void functionOne() override {/*implementation*/}
	void functionTwo() override {/*implementation*/}
        static const bool registered_ = ParamHolder::singleton().register(std::make_unique<ParamTwo>());
};

class ParamHolder {
public:
	void doAllFunctionOne() {
		for (size_t i = 0; i < params.size(); ++i) {
			params[i]->functionOne();
		}
	}

	void doOneFunctionTwo(ParamName p) {
		params[(int)p]->functionTwo();
	}

        bool register(std::unique_ptr<ParamBase> t) {
                // If you care about ordering you should sort the things somehow here.
                params.push_back(std::move(t));
        }
        static ParamHolder& singleton();  // You can look up how to do a singleton if you're not familiar.

private:

	std::vector<std::unique_ptr<ParamBase>> params;
};

cheetah7071
Oct 20, 2010

honk honk
College Slice
thanks! I'm already doing this as a singleton, I just left it out of the code snippet. Using a static variable that's defined as a function call that has side effects is a pretty neat way to do that, and one I definitely would never have thought of

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

cheetah7071 posted:

thanks! I'm already doing this as a singleton, I just left it out of the code snippet. Using a static variable that's defined as a function call that has side effects is a pretty neat way to do that, and one I definitely would never have thought of
As mentioned in the comment, if you care about ordering (or if any of the constructors interact with other things) you have to be careful, because static variables init-time order is undefined.

cheetah7071
Oct 20, 2010

honk honk
College Slice

roomforthetuna posted:

As mentioned in the comment, if you care about ordering (or if any of the constructors interact with other things) you have to be careful, because static variables init-time order is undefined.

I need to understand the ordering well enough for the function doOneFunctionTwo to work, but I think I can handle that by implementing a sorter function for ParamBase and sorting the list.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

cheetah7071 posted:

I need to understand the ordering well enough for the function doOneFunctionTwo to work, but I think I can handle that by implementing a sorter function for ParamBase and sorting the list.
Oh, right, didn't notice you were using the enum as an index for that. You can do something a bit wacky like if you #define the registration function you can make it also have a static constexpr char *name = "<the name of class>", also pass that to the register function, and then register the pointers in a std::unordered_map keyed on that char* (not the string, literally the pointer; uniqueness guaranteed, fast comparison). Then
code:
template <class T>
void doOneFunctionTwo() {
  params[T::name]->functionTwo();
}
There's a small performance cost of a hash versus a flat index though.

Another option, if you don't care about the order for the "doAll" variants, would be to have register return an index, set the static const initializer value to that index, and then like above but params[T::registered_index]->functionTwo() for the "doOne" variant.

And if you *do* care about the order for the "doAll" variant then you can specify the index in the register function (and debug-time validate that there's no index collisions or gaps).

cheetah7071
Oct 20, 2010

honk honk
College Slice
Thanks for the comprehensive help. I in fact do not care about the order for doAll so I'll probably go with the registered_index version

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.
Is there any easy way that I'm missing in C++ to quickly allocate memory for a vector of vectors? I'm doing a lot of relatively small allocations and it's slow.

I've got a genomics HPC application that I've been tuning to run better, that's what all the posting about vectorization was earlier. After making a pretty big win with massif to decrease peak memory usage, we're chasing better total throughput by launching many processes at the same time now that it uses less memory and we can fit more into a single worker node.

The application has three big phases: preparing a large, read-only data structure that's made up of a vector of 100k-1 million vectors of bytes, each 50k-1m bytes long, then spawning threads to do all its work as a single parser thread throws lines from the input onto a synchronized queue and all the worker threads pull from it, then write to a single output thread via a synchronized queue, and then at the end it sorts the output on a single thread using a fixed amount of memory.

We're running into Ahmdal's law where we have more wasted scheduled CPU time as we use more worker threads, and I've gotten the memory usage down to basically just the single large data structure + less than 100MB other stuff, so I'm trying to request less memory and thread and get a bunch of these packed onto a single worker node at once. The unexpected bottleneck is that the more processes we have in the allocation phase at once, the longer the allocation phase takes for all of them, in a pretty big way! I checked I/O metrics and we are not limited on disk I/O or apparently exhausting memory bandwidth (that I can see via a naiive check), so my question is:

Is there a system-wide memory allocation bottleneck? What could I do to alleviate this with a vector of vectors? Each vector is allocating via a complete copy from an existing vector, then mutating without ever adding more items, which should only allocate once. The set I'm testing this on is only allocating about 100k vectors of 60k bytes each, but having 20 processes sitting there on a single node is taking much longer than forecast on a less-loaded node.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Twerk from Home posted:

Is there any easy way that I'm missing in C++ to quickly allocate memory for a vector of vectors? I'm doing a lot of relatively small allocations and it's slow.

I've got a genomics HPC application that I've been tuning to run better, that's what all the posting about vectorization was earlier. After making a pretty big win with massif to decrease peak memory usage, we're chasing better total throughput by launching many processes at the same time now that it uses less memory and we can fit more into a single worker node.

The application has three big phases: preparing a large, read-only data structure that's made up of a vector of 100k-1 million vectors of bytes, each 50k-1m bytes long, then spawning threads to do all its work as a single parser thread throws lines from the input onto a synchronized queue and all the worker threads pull from it, then write to a single output thread via a synchronized queue, and then at the end it sorts the output on a single thread using a fixed amount of memory.

We're running into Ahmdal's law where we have more wasted scheduled CPU time as we use more worker threads, and I've gotten the memory usage down to basically just the single large data structure + less than 100MB other stuff, so I'm trying to request less memory and thread and get a bunch of these packed onto a single worker node at once. The unexpected bottleneck is that the more processes we have in the allocation phase at once, the longer the allocation phase takes for all of them, in a pretty big way! I checked I/O metrics and we are not limited on disk I/O or apparently exhausting memory bandwidth (that I can see via a naiive check), so my question is:

Is there a system-wide memory allocation bottleneck? What could I do to alleviate this with a vector of vectors? Each vector is allocating via a complete copy from an existing vector, then mutating without ever adding more items, which should only allocate once. The set I'm testing this on is only allocating about 100k vectors of 60k bytes each, but having 20 processes sitting there on a single node is taking much longer than forecast on a less-loaded node.

https://en.cppreference.com/w/cpp/container/vector/reserve ?

nielsm
Jun 1, 2009



Which language version are you on? On the newer versions it should be relatively painless to make an arena allocator where you can allocate one huge slab of memory and tell all the inner vectors to take their memory via that allocator. Those arena allocators can then be per-thread or whatever.
And also pre-allocate with vector.reserve(), instead of growing dynamically, if you know how many items you need.

Phobeste
Apr 9, 2006

never, like, count out Touchdown Tom, man

Twerk from Home posted:

Is there any easy way that I'm missing in C++ to quickly allocate memory for a vector of vectors? I'm doing a lot of relatively small allocations and it's slow.

I've got a genomics HPC application that I've been tuning to run better, that's what all the posting about vectorization was earlier. After making a pretty big win with massif to decrease peak memory usage, we're chasing better total throughput by launching many processes at the same time now that it uses less memory and we can fit more into a single worker node.

The application has three big phases: preparing a large, read-only data structure that's made up of a vector of 100k-1 million vectors of bytes, each 50k-1m bytes long, then spawning threads to do all its work as a single parser thread throws lines from the input onto a synchronized queue and all the worker threads pull from it, then write to a single output thread via a synchronized queue, and then at the end it sorts the output on a single thread using a fixed amount of memory.

We're running into Ahmdal's law where we have more wasted scheduled CPU time as we use more worker threads, and I've gotten the memory usage down to basically just the single large data structure + less than 100MB other stuff, so I'm trying to request less memory and thread and get a bunch of these packed onto a single worker node at once. The unexpected bottleneck is that the more processes we have in the allocation phase at once, the longer the allocation phase takes for all of them, in a pretty big way! I checked I/O metrics and we are not limited on disk I/O or apparently exhausting memory bandwidth (that I can see via a naiive check), so my question is:

Is there a system-wide memory allocation bottleneck? What could I do to alleviate this with a vector of vectors? Each vector is allocating via a complete copy from an existing vector, then mutating without ever adding more items, which should only allocate once. The set I'm testing this on is only allocating about 100k vectors of 60k bytes each, but having 20 processes sitting there on a single node is taking much longer than forecast on a less-loaded node.

can you split the ingest into
- pass 1: determine the number of datasets and the size of each dataset; heap-allocate a single chunk of memory as a std::array or using array-new that is large enough for both the data index vector and all the data vectors. placement-new the index vector into it at the beginning and reserve the required space. then go placement new all the data vectors in the rest of the space using your own pointer math and put their addresses in the index vector, same deal with reserving space
- pass 2: fill in the data

the benefit to this is it should cost fewer sbrk syscalls/pagefaults/whatever since you're just getting a big slab of memory for everything. there's also probably better ways and libraries to do this but really the core thing you need to do is to try and figure out how much memory you need before you need it.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
I wouldn't necessarily call it an "easy" way, but you could write a custom allocator that gives your vectors slices of a pre-allocated slab, instead of rummaging around freelists to make individual allocations for each vector. If you know all your vectors will have the same lifetime then it's actually not too bad to implement.

The malloc heap is usually single-threaded, and you can definitely get some real bad contention on the heap lock if you have a bunch of threads trying to do a lot of allocations at the same time.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...
What OS are you on, and are you using the default system malloc/new?
At least on Linux, the standard libc memory manger can have problems with multithreaded programs, if you’re using that it might be worth trying one of the drop in replacements like tcmalloc or jemalloc.

Xarn
Jun 26, 2015
yeah, generally your OS will want to do some bookkeeping, and some zeroing, while you are allocating memory. If you are in low pressure scenario, it can likely hide that in the background load and you are none the wiser. If you are hammering the allocations from multiple processes, the overhead has to happen.

I am not sure if I understand what you are doing with the allocations properly, but if you won't be resizing the vectors, you can make a single HUGE vector and then create a whole lot of spans into it. If you start resizing, you are dead though, and obviously you have to make sure that the different workers won't step on each other's toes.

Xarn fucked around with this message at 21:45 on Dec 6, 2022

Xarn
Jun 26, 2015
I am getting owned by C++20 changes to comparison operators. If you don't know them, the basic idea is that the compiler can assume quite a lot about comparison operators now, and rewrite them in expressions accordingly, so e.g. for equality it can check for both a == b and b == a and look for overloads matching either of these cases.

The issue is, this isn't always the case and now I have a very complex, constrained templated overload set of operator== that doesn't compile.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Xarn posted:

I am getting owned by C++20 changes to comparison operators. If you don't know them, the basic idea is that the compiler can assume quite a lot about comparison operators now, and rewrite them in expressions accordingly, so e.g. for equality it can check for both a == b and b == a and look for overloads matching either of these cases.

The issue is, this isn't always the case and now I have a very complex, constrained templated overload set of operator== that doesn't compile.

Lol owned.

Though I'm frightened about potential issues related to unity and il2cpp now.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

Xarn posted:

I am getting owned by C++20 changes to comparison operators. If you don't know them, the basic idea is that the compiler can assume quite a lot about comparison operators now, and rewrite them in expressions accordingly, so e.g. for equality it can check for both a == b and b == a and look for overloads matching either of these cases.

The issue is, this isn't always the case and now I have a very complex, constrained templated overload set of operator== that doesn't compile.

wait, what the gently caress did you do? did you overload == with a method that doesn't respect the symmetric property of equality?

Xarn
Jun 26, 2015
The results are symmetric, overloads are not :v:

Xarn
Jun 26, 2015
I am going with the stupid-but-works solution, and adding yet another hack on top. The compilers can go eat a dick.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Xarn posted:

The results are symmetric, overloads are not :v:

sounds like you can delete half your operators and have less code to maintain

Xarn
Jun 26, 2015
Not really, no. To make REQUIRE( a == b ) work, you need to inject your own type into it, so you end up with Decomposer{} <= a == b, which fundamentally requires the overloads to be crafted for LtR evaluation.

Anyway I actually figured out the issue, it is in fact extremely stupid. The fix is to move the SFINAE into return type instead of template parameter, so that the compiler does not have to start evaluating the SFINAE (and dying terribly) to figure out that the overload is not happening for given arguments. :tif:

This is why I have a love-hate-hate-hate-hate relationship with C++

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

Xarn posted:

Not really, no. To make REQUIRE( a == b ) work, you need to inject your own type into it, so you end up with Decomposer{} <= a == b, which fundamentally requires the overloads to be crafted for LtR evaluation.

Anyway I actually figured out the issue, it is in fact extremely stupid. The fix is to move the SFINAE into return type instead of template parameter, so that the compiler does not have to start evaluating the SFINAE (and dying terribly) to figure out that the overload is not happening for given arguments. :tif:

This is why I have a love-hate-hate-hate-hate relationship with C++

oh that makes sense but to be honest you're loving with parts of C++ that i would just not gently caress with voluntarily because i've been burned going down those routes before.

Xarn
Jun 26, 2015
If you aren't opening new bugs against compilers, do you even C++?

Absurd Alhazred
Mar 27, 2010

by Athanatos
Heh, yeah. I keep forgetting I actually did that two jobs ago. Something to do with the interaction of templates and lambdas. Gave them a repro and mitigations, I think they fixed it within a couple of days.

Nalin
Sep 29, 2007

Hair Elf
If you wanna have fun writing up compiler bug reports, just try to use C++20 modules in Visual Studio. I've ICE'ed the compiler a couple times already.

Absurd Alhazred
Mar 27, 2010

by Athanatos
Trust me, I've got a lot of other development middleware to crash in my day job.

Ihmemies
Oct 6, 2012

drat python is so slow. I made this AoC day 8 puzzle in python first, then cpp. Python was 90ms, cpp 7ms. I tried to implement them the same way.

matti
Mar 31, 2019

i have a question about the core guidelines, specifically ES.87 "Don’t add redundant == or != to conditions"

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-if

many C style guides recommend the opposite, i.e. always use explicit comparisons unless the value is boolean. the guideline does not explain what "opportunities for mistakes" redundant comparisons have. is it just a misplaced style rule or are there realistic traps explicit comparisons have in C++?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
In theory someone might write "if (p = nullptr)" instead of "if (p == nullptr)', which might be a problem if you're using a primitive text editor and a compiler from 1987 (or if you're the sort of person to turn off compiler warnings because you're convinced you know better).

AgentF
May 11, 2009

Ihmemies posted:

drat python is so slow. I made this AoC day 8 puzzle in python first, then cpp. Python was 90ms, cpp 7ms. I tried to implement them the same way.

Of course, it has an interpreter that goes through many more steps to do the same thing. But if you choose Python to begin with you've already depriorotised performance over some other quality, like speed of development or readability. If you're trying to implement Python the same way you would C++ then chances are it's been bent unergonomically away from how it's designed to be used (what's called the "Pythonic" approach).

Twerk from Home
Jan 17, 2009

This avatar brought to you by the 'save our dead gay forums' foundation.

nielsm posted:

Which language version are you on? On the newer versions it should be relatively painless to make an arena allocator where you can allocate one huge slab of memory and tell all the inner vectors to take their memory via that allocator. Those arena allocators can then be per-thread or whatever.
And also pre-allocate with vector.reserve(), instead of growing dynamically, if you know how many items you need.

Thanks for this, an arena allocator is exactly the kind of solution here, where I have a big vector of vectors of known size (at runtime) and the same lifetime.



I'm calling reserve on the vector that holds the vectors, and each subsequent vector is copy-assigned from an existing vector of the final length, which I hope will only allocate once. It's just that doing 100k-1m separate allocations is slow, because I have 100k-1m separate vectors.

I've got a big templated function that will have some small internal differences in flow based on what the template type actually is. Am I going to hate my life for using if constexpr, like

C++ code:
if constexpr (std::is_same<T, int8_t>::value) {
    // Specific code for T being a signed char
}
or is that a relatively safe and sanity-preserving path to go down? The alternative I see is duplicating a bunch of code by having a separate template<int8_t> version of the function. What scares me is that I know that typeid(T) and std::is_same<T, whatever> behave differently, but typeid(T) is runtime only.

cheetah7071
Oct 20, 2010

honk honk
College Slice
Could you not put the slight bits of different code into templated functions with template specifications? If the function is inline it should compile to the same thing but it'll probably be more readable

Adbot
ADBOT LOVES YOU

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
if constexpr is infinitely more readable than splitting poo poo into separate functions purely for the sake of working around not having if constexpr.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply