Showing posts with label efficiency. Show all posts
Showing posts with label efficiency. Show all posts
Thursday, May 2, 2013
Loot Run Postmortem
While I did not particularly like the theme of Ludum Dare #26 as it was far too general, I did have Saturday free to work on so I created a quick game. To me minimalism means eliminating all that is unnecessary. For games, this means graphics and sound. The idea is to focus on the essential gameplay. Loot Run is a platform game done entirely with text.
What Went Right
Keeping with the theme, I wanted to keep the gameplay as simple as possible while still being fun. While scrolling would have been easy to do, keeping levels limited to a single screen seemed to fit the theme better. The player needs an objective. Collecting money is a very obvious motivation and is something that most players can relate to. Having just the environment as the obstacle did not seem like enough so monsters were added. While the original plans called for title, instructions, winning and about screens, it became obvious that these things could be integrated right into the game levels.
What was Both Right and Wrong
Using just text was the right decision, but in hindsight it would have been more efficient to use a canvas with the letters as a tile set. This would have resulted in a lot less garbage collection. While this had little impact on the game, knowing that all the needless garbage collection is happening does bother me. For those not familiar with JavaScript, let me briefly explain.
JavaScript strings are immutable. This means that every time you modify a string you are actually creating a new string and essentially dumping the old string onto the garbage heap. When there are enough dead strings lying about the garbage collector gets called and frees up the memory. As generating a frame results in numerous dead strings, this is not very efficient. It is kind of ironic that faking strings by using tile-maps would have been more efficient.
What went Wrong
The controls for the game were probably the biggest problem. The method I used was to track whether keys were up or down and during the main event loop adjusting the player based on the keys. For most games this would be fine but because I am only updating the frame every 150ms this can result in too big of a lag between the players key press and the processing. For instance, if a player hits up to jump and releases the key within the 150ms it is possible that the jump will be missed. What I should have done is had an array for next actions as well as key states. The next action would have been set as soon as a key was pressed, and every interval the actions would be ORed with the keys that are still down.
Sunday, May 23, 2010
Why ActionScript and JavaScript are Slow
Slow is a relative term. Compared to the Commodore 64 that I use to program, today's computers are incredibly fast. Still, a lot of complaints about JavaScript and ActionScript (the scripting language Flash uses) is how slow they are. While both ActionScript and JavaScript use JIT compilers to greatly improve the speed of the code, there is overhead in compiling. Some proponents of "real" programming languages will say that this is still not as fast as a proper compiled language would produce. As someone who has programmed in a variety of Machine Languages, I should point out that compiled languages do not produce as good of code as hand-coded assembly language will produce. Some compiler makers claim that their compiled code is better than what the average assembly language programmer would produce. This is possibly true if that assembly language programmer was converting the higher level language line by line into assembly language like a compiler does, but if he or she is writing the routine from scratch the results would likely favour the programmer.
While some of the speed difference can be attributed to the nature of JIT compiled code, I think the bigger problem is that both ActionScript and JavaScript were designed to be easy to write code for. Remember that although these languages are now being used for more serious projects, they were intended to be for adding more flexibility to web pages or animations. In theory, these languages are suppose to be accessible to anybody, though if you look at more complex project, it is clear that real programming is still at the heart of these languages.
Concepts like dynamic objects definitely make these languages far more flexible than older languages like C/C++ but flexibility has a lot of overhead. Instead of just calling a function directly, the language has to go to the object in memory and find the pointer to the function (as it may have changed from the default one) before making the function call. It may not be much of an overhead, but it does add up. Then there is the issue of the libraries included with these languages. Using Strings for a lot of things that other libraries would have used integers for has a drastic effect on performance. If you used an integer, you would have one quick comparison to do. When you use a string, each letter of the string has to be compared. Using strings certainly makes it easier to program but there is a big cost in speed.
I could probably go on for pages, but ultimately, what it comes down to is that these languages are easier for humans to write code at a cost of efficiency, but as JIT compilers get better, the difference is not as great as purists would like to believe and the much greater productivity that results probably outweighs the speed costs.
While some of the speed difference can be attributed to the nature of JIT compiled code, I think the bigger problem is that both ActionScript and JavaScript were designed to be easy to write code for. Remember that although these languages are now being used for more serious projects, they were intended to be for adding more flexibility to web pages or animations. In theory, these languages are suppose to be accessible to anybody, though if you look at more complex project, it is clear that real programming is still at the heart of these languages.
Concepts like dynamic objects definitely make these languages far more flexible than older languages like C/C++ but flexibility has a lot of overhead. Instead of just calling a function directly, the language has to go to the object in memory and find the pointer to the function (as it may have changed from the default one) before making the function call. It may not be much of an overhead, but it does add up. Then there is the issue of the libraries included with these languages. Using Strings for a lot of things that other libraries would have used integers for has a drastic effect on performance. If you used an integer, you would have one quick comparison to do. When you use a string, each letter of the string has to be compared. Using strings certainly makes it easier to program but there is a big cost in speed.
I could probably go on for pages, but ultimately, what it comes down to is that these languages are easier for humans to write code at a cost of efficiency, but as JIT compilers get better, the difference is not as great as purists would like to believe and the much greater productivity that results probably outweighs the speed costs.
Sunday, March 7, 2010
Programming, the Coming of Language
(Continued from Programming, the Early Years)
The thought was that if the languages would be more human like so it would be easy for people to create software then there would be no need for programmers. The earliest programming languages were created to allow scientists and researchers the ability to write programs themselves which is why FORTRAN is considered to be the first high-level programming language. The idea here being that The programs in these higher level languages would be run through a tool called a compiler which either converted the program into assembly language (which would then have to be ran through an assembler) or straight into machine language.
While higher level languages made it easier to create programs, learning how to program was still a chore. The fact that the programs were ran in batches so there was a long delay between writing code and seeing the results was the biggest culprit. Computers, thankfully, continued to grow in power to the point that there were a lot of waisted computer cycles. To better utilize the hardware, time-sharing systems and terminals started appearing. This lead to the obvious idea of having programming languages that were interactive in nature. By interpreting the code instead of compiling the code it was possible to write programs in real time. The downside to interpreters were that they were significantly slower than compilers.
Another issue that was becoming bothersome was the fact that every machine had a different machine language. Sure, you could simply write programs in high level languages and compile it for the different computers that the program had to be ran on, but different compilers for the same language would compile the code differently so idiosyncrasies were common place. The term for moving code from one computer to another is porting. The fact that a term was created to describe this problem (which still persists today) should tell you that it was not a trivial problem. UCSD Pascal solved this problem by compiling code to a virtual p-machine language. The computer would then interpret this virtual p-code. Because p-code was essentially machine language, the computer could interpret this code much faster than an interpreted language could be ran. Still, it was slower than code compiled for a particular machine. When micro-computers started taking off, the speed difference became a big factor in commercial software sales.
While it seemed that compiled code won, computers continued to grow faster to the point where they were more than fast enough to accomplish most common tasks. At the same time, the internet started taking off. Sites wanted to be more dynamic but had to be not only cross-platform but cross-browser compatible. Both interpreters (JavaScript) and virtual machines (Java) were used to accomplish this. To make the virtual machine fast enough, a new technique called Just-In-Time compiling was developed. The idea here is that the virtual machine code is compiled into native machine language as it is ran so code will run much faster.
The concept of a virtual machine running on the browser seemed to me to be the best solution. Sadly, for a variety of reasons Java never became the browser language of choice but instead ended up largely on the server. Flash is currently the virtual machine of choice for browser programming, but JavaScript is probably the most common choice for web development. The only thing holding JavaScript back is the lack of some of the Rich Internet Application features, but HTML 5 is pretty much solving those issues. It will be a few years before HTML 5 becomes the standard, but with Google, Apple, and Mozilla pushing for the standard it is possible to take advantage of a lot of HTML 5s features right now.
So we have gone from writing code in machine language to compiling the code into machine language to running the code in an interpreter. What is really interesting is that changes in hardware is what drove programming evolution. Computers are now so fast and have so much memory that programmers no longer need to concern themselves with writing efficient code. What matters now is that the code that is written is finished quickly. Sure, many programmers want to write efficient code but they only have to write efficient code in the increasingly rare case where the program runs too slow. What is worse is the fact that programming has moved further away from machine language that there are many programmers who don't really understand what the computer is actually doing. That, however, is a subject for another day.
The thought was that if the languages would be more human like so it would be easy for people to create software then there would be no need for programmers. The earliest programming languages were created to allow scientists and researchers the ability to write programs themselves which is why FORTRAN is considered to be the first high-level programming language. The idea here being that The programs in these higher level languages would be run through a tool called a compiler which either converted the program into assembly language (which would then have to be ran through an assembler) or straight into machine language.
While higher level languages made it easier to create programs, learning how to program was still a chore. The fact that the programs were ran in batches so there was a long delay between writing code and seeing the results was the biggest culprit. Computers, thankfully, continued to grow in power to the point that there were a lot of waisted computer cycles. To better utilize the hardware, time-sharing systems and terminals started appearing. This lead to the obvious idea of having programming languages that were interactive in nature. By interpreting the code instead of compiling the code it was possible to write programs in real time. The downside to interpreters were that they were significantly slower than compilers.
Another issue that was becoming bothersome was the fact that every machine had a different machine language. Sure, you could simply write programs in high level languages and compile it for the different computers that the program had to be ran on, but different compilers for the same language would compile the code differently so idiosyncrasies were common place. The term for moving code from one computer to another is porting. The fact that a term was created to describe this problem (which still persists today) should tell you that it was not a trivial problem. UCSD Pascal solved this problem by compiling code to a virtual p-machine language. The computer would then interpret this virtual p-code. Because p-code was essentially machine language, the computer could interpret this code much faster than an interpreted language could be ran. Still, it was slower than code compiled for a particular machine. When micro-computers started taking off, the speed difference became a big factor in commercial software sales.
While it seemed that compiled code won, computers continued to grow faster to the point where they were more than fast enough to accomplish most common tasks. At the same time, the internet started taking off. Sites wanted to be more dynamic but had to be not only cross-platform but cross-browser compatible. Both interpreters (JavaScript) and virtual machines (Java) were used to accomplish this. To make the virtual machine fast enough, a new technique called Just-In-Time compiling was developed. The idea here is that the virtual machine code is compiled into native machine language as it is ran so code will run much faster.
The concept of a virtual machine running on the browser seemed to me to be the best solution. Sadly, for a variety of reasons Java never became the browser language of choice but instead ended up largely on the server. Flash is currently the virtual machine of choice for browser programming, but JavaScript is probably the most common choice for web development. The only thing holding JavaScript back is the lack of some of the Rich Internet Application features, but HTML 5 is pretty much solving those issues. It will be a few years before HTML 5 becomes the standard, but with Google, Apple, and Mozilla pushing for the standard it is possible to take advantage of a lot of HTML 5s features right now.
So we have gone from writing code in machine language to compiling the code into machine language to running the code in an interpreter. What is really interesting is that changes in hardware is what drove programming evolution. Computers are now so fast and have so much memory that programmers no longer need to concern themselves with writing efficient code. What matters now is that the code that is written is finished quickly. Sure, many programmers want to write efficient code but they only have to write efficient code in the increasingly rare case where the program runs too slow. What is worse is the fact that programming has moved further away from machine language that there are many programmers who don't really understand what the computer is actually doing. That, however, is a subject for another day.
Sunday, February 21, 2010
Programming, the Early Years
Efficient code is not as important as it use to be. What is worse is that the situation is getting worse not better. While the vital parts of a program are likely to be written efficiently, a growing percentage of the code is going to be quickly written and probably inefficient. Making this situation even worse is that the code being written is often going to be interpreted or ran on a virtual machine. To understand why this is the case and why things will get worse before they get better one just has to look at how programming has evolved over the years.
The earliest computers were programmed in machine language. In the very early days this was done by re-wiring machine components though this quickly changed to flipping switches and then into punched cards or paper tape. Computers were huge expensive machines so every second of machine time was precious. Programs were often ran in batches meaning that you would submit your cards or tape and wait (sometime days or weeks) to get your results. When you got your results, if there were problems then you would have to re-submit. As computer time was golden, sloppy code was frowned upon. Likewise, because there was a fair amount of time between tests, programmers had plenty of time to make sure their code was well written.
Computer programs were much simpler back then due to the fact that the machines had almost no memory and were slow. Memory in early computers were measured in Kilo-words with the number of bits in a word being machine specific though 18 seemed to be a common number. A gigabyte is 1,048,576 kilobytes or 1,073,741,824 bytes so to think back in terms of kilo-words is scary. Speed was in kilohertz. Yes, a gigahertz is 1,000,000 kilohertz. Still, programming in Machine Language would have been painful work. What most programmers did was write their programs in an English-like format where machine instructions were given simple names such as LOAD, STORE, JUMP. This code was then converted into the numbers that had to be put into the computer.
Hand coding machine language was a big waist of programmer time, but the cost of programmers was a lot less than the machines that were being programmed. I am sure that many early programmers came up with the idea of a tool that would take a human readable form of machine language and converting it into the actual machine language instructions. It wasn 't until the 1950s that such programs started being used. This made programming much more efficient. When a program was written in assembly language, it had to be run through a program called an assembler which converted a human-readable form of machine language into a machine-readable form of machine language. While this added an extra step to the process, the assembly step only had to be done once and the resulting output could then be used any number of times. The assembler resulted in boosted productivity for the programmers.
The cost of computers began to decline while the capabilities continued to grow. This resulted in computers becoming more common. Soon big business and research facilities all wanted to have their own computers. The problem with computers then became the requirement for programmers to write the programs in assembly language (which at this point was starting to be referred to as machine language even though technically speaking there is a difference). If only there was a way for "normal" people to write programs.
This article will continue in a couple of weeks as next week I will be writing about the March release on Blazing Games which is a game that came from a quick protoype I created. This game is an example of how plans for a game can drastically change.
The earliest computers were programmed in machine language. In the very early days this was done by re-wiring machine components though this quickly changed to flipping switches and then into punched cards or paper tape. Computers were huge expensive machines so every second of machine time was precious. Programs were often ran in batches meaning that you would submit your cards or tape and wait (sometime days or weeks) to get your results. When you got your results, if there were problems then you would have to re-submit. As computer time was golden, sloppy code was frowned upon. Likewise, because there was a fair amount of time between tests, programmers had plenty of time to make sure their code was well written.
Computer programs were much simpler back then due to the fact that the machines had almost no memory and were slow. Memory in early computers were measured in Kilo-words with the number of bits in a word being machine specific though 18 seemed to be a common number. A gigabyte is 1,048,576 kilobytes or 1,073,741,824 bytes so to think back in terms of kilo-words is scary. Speed was in kilohertz. Yes, a gigahertz is 1,000,000 kilohertz. Still, programming in Machine Language would have been painful work. What most programmers did was write their programs in an English-like format where machine instructions were given simple names such as LOAD, STORE, JUMP. This code was then converted into the numbers that had to be put into the computer.
Hand coding machine language was a big waist of programmer time, but the cost of programmers was a lot less than the machines that were being programmed. I am sure that many early programmers came up with the idea of a tool that would take a human readable form of machine language and converting it into the actual machine language instructions. It wasn 't until the 1950s that such programs started being used. This made programming much more efficient. When a program was written in assembly language, it had to be run through a program called an assembler which converted a human-readable form of machine language into a machine-readable form of machine language. While this added an extra step to the process, the assembly step only had to be done once and the resulting output could then be used any number of times. The assembler resulted in boosted productivity for the programmers.
The cost of computers began to decline while the capabilities continued to grow. This resulted in computers becoming more common. Soon big business and research facilities all wanted to have their own computers. The problem with computers then became the requirement for programmers to write the programs in assembly language (which at this point was starting to be referred to as machine language even though technically speaking there is a difference). If only there was a way for "normal" people to write programs.
This article will continue in a couple of weeks as next week I will be writing about the March release on Blazing Games which is a game that came from a quick protoype I created. This game is an example of how plans for a game can drastically change.
Friday, February 5, 2010
Is efficient code obsolete?
I was looking over some of my older code noting how inefficient some of my code was. There were a number of reasons for this. The biggest is my very short development time. In my case, the short schedules are the result of my desire to release a lot of material. I have tried to slow down my release schedule to allow for better content, but other things always seem to creep in to steal my spare time. Unrealistic schedules are far too common in the tech industry and is made worse by the fact that the vast majority of people in charge have no clue how software works or how much work is involved in its creation. Making this problem worse are the programmers themselves who often vastly under-estimate the work required to complete a project. Short development time leads to focusing on just getting the code to work not on getting the code to work as efficiently as possible.
Related to the short development time is the fact that often I will cut and paste similar code from earlier projects that I have worked on. I restrict myself to code that I have written, though there are many programmers who will cut and paste from other peoples' code. By tweaking existing code, you can implement something very quickly. The problem is that often the code you are borrowing may have stuff in it that you are not using within the new project but that was necessary in the original project. The fact that you are cutting and pasting code probably means you are in a hurry which means that the redundant and unnecessary code that is copied will remain resulting in both code bloat and inefficient code. Changing project specifications in the middle of a project, which is sadly far to common, also results in unnecessary code bloat for similar reasons.
A third common reason for my inefficient code is that the code in question is not going to be executed very often. This is related to the first reason due to the obvious fact that functions that are infrequently used are going to be written fairly quickly. Another reason that infrequently executed code tends to be inefficient is that there is very little incentive to optimize the code as the inefficiency of rarely executed code is not going to noticeably impact the overall speed of the program. Optimising a program takes time so that effort should be placed on the parts of a program that are executed frequently or that are most critical to the speed of a program.
Not all of my reasons are related to development time. I often will write code that I can easily understand instead of using more efficient code that was harder to grok. For example:
c = Math.min(a,b);
This code obviously sets c to be the lower of the values a or b. It is, however, making a function call which has overhead and if the function call uses floating point while the variables used are integer you have a number of type conversions as well. Many languages have generics and will inline small code blocks right into the code if compiler optimisation is enabled which can mitigate the speed difference. In the best case, the compiler would essentially convert the function call into the following statement:
c = (a < b) ? a : b;
If you were to use the second version of the code instead of the first, you would be guaranteed no function call or type conversion overhead. I find first version much easier to understand, but depending on your compiler it could be substantially slower than the second version. The difference is in the millionth of a second, though.
None of this even gets into the facts that the code being written is often going to be interpreted or ran on a virtual machine. Likewise, the speed of computers is not looked at. Worst of all, the fact that programmers are no longer familiar with low level programming so write code that doesn't compile efficiently is not addressed. Those are topics for another column or three. Still, the conclusion that I have come up with is the simple one that computer time is far cheaper than programmer time which is cheaper than time-to-market time so it is safe to say that while writing efficient code is still something to be aimed for, getting code out quickly is sadly the bigger priority.
Related to the short development time is the fact that often I will cut and paste similar code from earlier projects that I have worked on. I restrict myself to code that I have written, though there are many programmers who will cut and paste from other peoples' code. By tweaking existing code, you can implement something very quickly. The problem is that often the code you are borrowing may have stuff in it that you are not using within the new project but that was necessary in the original project. The fact that you are cutting and pasting code probably means you are in a hurry which means that the redundant and unnecessary code that is copied will remain resulting in both code bloat and inefficient code. Changing project specifications in the middle of a project, which is sadly far to common, also results in unnecessary code bloat for similar reasons.
A third common reason for my inefficient code is that the code in question is not going to be executed very often. This is related to the first reason due to the obvious fact that functions that are infrequently used are going to be written fairly quickly. Another reason that infrequently executed code tends to be inefficient is that there is very little incentive to optimize the code as the inefficiency of rarely executed code is not going to noticeably impact the overall speed of the program. Optimising a program takes time so that effort should be placed on the parts of a program that are executed frequently or that are most critical to the speed of a program.
Not all of my reasons are related to development time. I often will write code that I can easily understand instead of using more efficient code that was harder to grok. For example:
c = Math.min(a,b);
This code obviously sets c to be the lower of the values a or b. It is, however, making a function call which has overhead and if the function call uses floating point while the variables used are integer you have a number of type conversions as well. Many languages have generics and will inline small code blocks right into the code if compiler optimisation is enabled which can mitigate the speed difference. In the best case, the compiler would essentially convert the function call into the following statement:
c = (a < b) ? a : b;
If you were to use the second version of the code instead of the first, you would be guaranteed no function call or type conversion overhead. I find first version much easier to understand, but depending on your compiler it could be substantially slower than the second version. The difference is in the millionth of a second, though.
None of this even gets into the facts that the code being written is often going to be interpreted or ran on a virtual machine. Likewise, the speed of computers is not looked at. Worst of all, the fact that programmers are no longer familiar with low level programming so write code that doesn't compile efficiently is not addressed. Those are topics for another column or three. Still, the conclusion that I have come up with is the simple one that computer time is far cheaper than programmer time which is cheaper than time-to-market time so it is safe to say that while writing efficient code is still something to be aimed for, getting code out quickly is sadly the bigger priority.
Subscribe to:
Posts (Atom)