Thread overview | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 10, 2010 slow runtime | ||||
---|---|---|---|---|
| ||||
The class code below runs terribly slow. Conversely, when converted into a function (albeit returning only one value), it runs fast. Any insights into this or suggestions to get a function to return multiple types at once? ...library code... module testlib; import std.stdio, std.string; class classtest { int i, j; double[][] hit() { double[][] hi = new double[][](1000, 40); for(i = 1; i < 1000; i++) { for(j = 1; j < 40; j++) { hi[i][j] = (i); } } return hi; } double[][] hot() { double[][] ho = new double[][](1000, 40); for(i = 1; i < 1000; i++) { for(j = 1; j < 40; j++) { ho[i][j] = (j); } } return ho; } string stest () { string hello = "yo!"; return hello; } } ... calling code ... import std.stdio, std.string; import testlib; void main() { classtest obj = new classtest; int i, j; for(i = 1; i < obj.hit.length; i++) { for(j = 1; j < obj.hit[i].length; j++) { writefln("%s\t%f\t%f", obj.stest, obj.hit[i][j], obj.hot[i][j]); } } } |
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dr. Smith | On Thursday 09 September 2010 19:40:47 Dr. Smith wrote:
> The class code below runs terribly slow. Conversely, when converted into a function (albeit returning only one value), it runs fast. Any insights into this or suggestions to get a function to return multiple types at once?
>
> ...library code...
>
> module testlib;
> import std.stdio, std.string;
>
> class classtest {
>
> int i, j;
>
> double[][] hit() {
>
> double[][] hi = new double[][](1000, 40);
>
> for(i = 1; i < 1000; i++) {
> for(j = 1; j < 40; j++) {
> hi[i][j] = (i);
> }
> }
> return hi;
> }
>
> double[][] hot() {
>
> double[][] ho = new double[][](1000, 40);
>
> for(i = 1; i < 1000; i++) {
> for(j = 1; j < 40; j++) {
> ho[i][j] = (j);
> }
> }
> return ho;
> }
>
> string stest () {
> string hello = "yo!";
> return hello;
> }
> }
>
> ... calling code ...
>
> import std.stdio, std.string;
> import testlib;
>
> void main() {
>
> classtest obj = new classtest;
> int i, j;
>
> for(i = 1; i < obj.hit.length; i++) {
> for(j = 1; j < obj.hit[i].length; j++) {
> writefln("%s\t%f\t%f", obj.stest, obj.hit[i][j], obj.hot[i][j]);
> }
> }
> }
Ouch. Woh. And ouch. LOL. Do you realize that _every time_ that you use hit or hot in main(), you're calling hit() and hot() and creating them all over again? Currently, functions which don't take any parameters and return a value and functions which take a single paramater and don't return anything are callable as if they were member variables. The correct way to do this is to mark them with @property, and eventually functions not marked with @property won't be useable as properties (so you'll have to call them explicitly), and functions marked with @property will have to be used as properties rathen than called explicitly, but dmd hasn't been updated to that point yet.
If you were to just assign hit() and hot() to local variables which you called, it would be a _lot_ faster. Now, it makes no sense for i or j to be member variables of your class since you just reset them every time that you use them, and it makes no sense for any of your functions to be part of a class, so they don't use any state from the class, but that's a separate issue. The problem here is that you keep calling hit() and hot() over and over. You end up with on O(n^4) algorithm instead of O(n^2). Painful indeed.
- Jonathan M Davis
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Related: Do stack variables get freed on exit or do they just get marked as unused by the GC? Because I'm not seeing any memory increase over time. I guess I have to read more about how allocation works. :p
Jonathan M Davis Wrote:
_every time_ that you use hit or
> hot in main(), you're calling hit() and hot() and creating them all over again
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dr. Smith | On Thursday 09 September 2010 19:40:47 Dr. Smith wrote:
> The class code below runs terribly slow. Conversely, when converted into a function (albeit returning only one value), it runs fast. Any insights into this or suggestions to get a function to return multiple types at once?
>
> ...library code...
>
> module testlib;
> import std.stdio, std.string;
>
> class classtest {
>
> int i, j;
>
> double[][] hit() {
>
> double[][] hi = new double[][](1000, 40);
>
> for(i = 1; i < 1000; i++) {
> for(j = 1; j < 40; j++) {
> hi[i][j] = (i);
> }
> }
> return hi;
> }
>
> double[][] hot() {
>
> double[][] ho = new double[][](1000, 40);
>
> for(i = 1; i < 1000; i++) {
> for(j = 1; j < 40; j++) {
> ho[i][j] = (j);
> }
> }
> return ho;
> }
>
> string stest () {
> string hello = "yo!";
> return hello;
> }
> }
>
> ... calling code ...
>
> import std.stdio, std.string;
> import testlib;
>
> void main() {
>
> classtest obj = new classtest;
> int i, j;
>
> for(i = 1; i < obj.hit.length; i++) {
> for(j = 1; j < obj.hit[i].length; j++) {
> writefln("%s\t%f\t%f", obj.stest, obj.hit[i][j], obj.hot[i][j]);
> }
> }
> }
By the way, it looks like what you're trying to do could be shrunk down to
import std.stdio;
void main()
{
for(float i = 1; i < 1000; ++i)
{
for(float j = 1; j < 40; ++j)
writefln("yo!\t%f\t%f", i, j);
}
}
and that runs _way_ faster. I don't understand why you're doing anything with arrays in the first place given what you're printing. But maybe you're just trying to show a simplified test case.
- Jonathan M Davis
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan, thank you for the quick response. I made some changes as you suggested and got much more speed. For some code that I'd like to convert to D, I am exploring the pros and cons of constructing a class library (versus a C like function library). My code here is just part of that exploration. ... the improved calling code ... import std.stdio, std.string; import testlib; void main() { classtest obj = new classtest; double[][] a = obj.hit; double[][] b = obj.hot; string c = obj.stest; int i, j; for(i = 1; i < a.length; i++) { for(j = 1; j < a[i].length; j++) { writefln("%s\t%f\t%f", c, a[i][j], b[i][j]); } } } |
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Andrej Mitrovic | On Thursday 09 September 2010 20:17:23 Andrej Mitrovic wrote:
> Related: Do stack variables get freed on exit or do they just get marked as unused by the GC? Because I'm not seeing any memory increase over time. I guess I have to read more about how allocation works. :p
>
> Jonathan M Davis Wrote:
>
> _every time_ that you use hit or
>
> > hot in main(), you're calling hit() and hot() and creating them all over
> > again
A variable on the stack has nothing to do with the GC unless it's in a delegate (since then the delegate must have its stack in a separate area on the heap). Now, dynamic arrays live on the stack, even if their references don't, so allocating a bunch of those will obviously require more memory. However, in this case, he's done with the array as soon as he's used it, so the GC (which if I understand correctly is called every time that new() is - or at least has the opportunity to run every time that new() is called) can reclaim it right away. There's a decent chance that he only ever allocates one array's worth of memory from the OS. Certainly, he wouldn't end up allocating new memory from the OS every time that he calls hit() or hot().
Every time that new is called, the GC will allocate the memory that it's asked to from its heap. At least some of the time that new is called, the GC will check to see if any of its heap memory can be recovered, and then recover it (so it's deallocated from the programs perspective but not returned to the OS). If the GC needs more memory than it has free on its heap, it will allocate more from the OS. Ideally, the GC would also look at how much memory that it has in its heap vs how much the program is currently using and then return some of it to the OS if it has too much free, but as I understand it, it doesn't currently do that. So, once your program uses a certain amount of memory, it won't ever use any less until it terminates. Presumably, that will be fixed at some point though.
- Jonathan M Davis
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dr. Smith | On Thursday 09 September 2010 20:54:15 Dr. Smith wrote:
> Jonathan, thank you for the quick response. I made some changes as you suggested and got much more speed. For some code that I'd like to convert to D, I am exploring the pros and cons of constructing a class library (versus a C like function library). My code here is just part of that exploration.
>
> ... the improved calling code ...
>
> import std.stdio, std.string;
> import testlib;
>
> void main() {
>
> classtest obj = new classtest;
> double[][] a = obj.hit;
> double[][] b = obj.hot;
> string c = obj.stest;
>
> int i, j;
>
> for(i = 1; i < a.length; i++) {
> for(j = 1; j < a[i].length; j++) {
> writefln("%s\t%f\t%f", c, a[i][j], b[i][j]);
> }
> }
> }
The other thing to consider is structs vs classes. Structs are value types which live on the heap and have no inheritance or polymorphism. Classes are reference types which live on the heap and have both inheritance and polymorphism. The general rule is to make something a struct unless you need inheritance and polymorphism (though obviously other things make factor into that choice).
Also, if you're serious about learning D, I'd definitely recommend picking up Andrei's book, "The D Programming Language." It's far more detailed and up-to- date than any of the online docs (though dmd isn't quite yet up-to-date in comparison to the book on all counts - the @property issue that you ran into being one). If you're just dabbling in D, it may not be worth the cost, but if you really want to be using D, then I think that it's well worth the cost.
- Jonathan M Davis
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan M Davis:
> Now, dynamic arrays live on the stack, even if their references don't,
Dynamic arrays are generally on the heap.
Bye,
bearophile
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Thursday 09 September 2010 23:23:45 bearophile wrote:
> Jonathan M Davis:
> > Now, dynamic arrays live on the stack, even if their references don't,
>
> Dynamic arrays are generally on the heap.
>
> Bye,
> bearophile
Aren't they _always_ on the heap? Their references are obviously on the stack, but as I understood it, the dynamic arrays themselves were always on the heap. Maybe scope could put them on the stack, but since scope is going away in that context, it doesn't really count.
- Jonathan M Davis
|
September 10, 2010 Re: slow runtime | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jonathan M Davis | Jonathan M Davis:
> Aren't they _always_ on the heap?
void main() {
int[10] a;
int[] b = a[];
}
Bye,
bearophile
|
Copyright © 1999-2021 by the D Language Foundation