This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Does an emulator out there exist with a feature like this?

Does an emulator out there exist with a feature like this?
by on (#54009)
I wasn't really sure where this should go...

I'm writing a multidirectional scrolling platforming game with collision detection for any angle of slope line you can give it. (Well... with a few restrictions.)

Now that it has gotten to a playable state the worries that I'm not a good enough programmer to make everything planned run fast enough for NES are beginning to take form.

So I am looking for an emulator that might do that following, or an emulator author that might add the following. None of it's NEEDED, but I'd sure like to see them.

The ability to see an average of how many cycles a subroutine/block of code (given a starting, and ending address for the subroutine/block of code) takes, and how many times the starting address is executed to see how many iterations went into the average. It could keep track of the least number of cycles, and the most number of cycles the block of code took overall as well. It'd also be nice to see the number of times the routine was run in the last frame, and the number of cycles it collectively took in the last frame. (Maybe an average for the last frame, but it's much less important)

You might say I could just add breakpoints to any current emu debugger and use the PPU cycles to figure it out. That could work but it's very tedious and doesn't help me figure out a good average anyway. Take my routine for storing metatiles from screens in ROM into RAM. I have 42 screens that could possibly be decoded, and some of them certainly appear more than others. This routine is run at least twice every time the scroll passes a screen boundary to write the two new screens to RAM. Some (single) screens take 2.5% of the frame time. Some take maybe 5-7.5%. Planning for the worst case scenario would be a great idea normally, but the worst case scenario set of two screens takes up 25% percent of the frame time. But that will NEVER ever happen unless I create some truly stupid level data. And finding a possible worst case scenario involves me going through each screen that's created. Though that routine is called so rarely that I don't care if it's slow. I'm not going to lose any sleep if the game loses a frame when the game needs to update these tiles.

My routine that checks for collisions is the real culprit, because it's run quite a few times in each frame, and its worse case scenario is pretty terrifying, but it's impossible for it to come up EVERY time the routine is called. And the routine's BEST case scenario is fast enough, and occurs more often, I think. This routine is especially hard to test every case for, because it depends on the collision line, and how many pixels away the user is for both X and Y. This routine is the real reason I want this, since it basically runs the whole game, and I'm running out of clever ideas to make it faster.

Honestly, I want this feature to know if I should give up or not on the game, since it's becoming very difficult for me to tell if it can really work quickly as planned, but I'd use it a lot if I don't give up as well. I may just have to change the style of game to something more like N+ (with little or no enemies) with this information. The game will certainly be fast enough with just a character and a scrolling map. I'm just worried that with the massive amount of CPU cycles just the main character's routine takes up, that even very few enemies might make the game slow down. So am I a baby for wanting such a thing? Are there any other strange features you would like to see in an emulator? Discuss! :lol:
Re: Does an emulator out there exist with a feature like thi
by on (#54012)
Kasumi wrote:
I wasn't really sure where this should go...


The main NESdev forum seems most appropriate, since this is a coding/testing issue. I'll move it so maybe it'll get better answers.

See the last post in this thread, and try the profiling version of VirtuaNES. I asked for a feature similar to what you want, and that's what I got.
http://nesdev.com/bbs/viewtopic.php?t=5289

It has been so long since I used it, that I forget how it worked now. I'm thinking that it was writing to $4018 and $4019 that begins and ends the profiling. But if that doesn't work, let me know and I will dig through my old sources to find where/how I used it.

edit: It is $401E/$401F, as miau discovered.

by on (#54045)
Ah! I remembered that post when it was made, but quit when the emulator complained for a language plugin. I took some initiative this time, and got one from a recent version of the program.

It doesn't seem to be $4018, and $4019 though. When I write them the displayed cyc, ave, and max values don't change. I would appreciate it if you could figure out the right registers. This looks like what I want.

by on (#54047)
You could also try using the logging feature of Nintendulator. It lets you log all executed instructions to a file, you could write a custom program to parse that data. I made an application to simply find out how many times each address was executed to get some profiling data. The problem is the log file gets quite big quite fast.

Here's the C++ source in case anybody wants it:
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <algorithm>

using namespace std;

struct AccessData {
    AccessData() : count(0) {}
    int count;
    string first_line;
    unsigned short addr;
};

bool AccessSort(AccessData *i, AccessData *j)
{
    if(i->count != j->count) {
        return i->count > j->count;
    } else {
        return i->addr < j->addr;
    }
}

int main()
{
    ifstream ifs("demo.20090801_122806.debug");

    string line;
    typedef map<unsigned short, AccessData> AccessCount;
    typedef vector<AccessData *> AccessCountPtrs;
    AccessCount access_counts;
    AccessCountPtrs access_count_ptrs;

    while(getline(ifs, line)) {
        istringstream iss(line);
        unsigned short addr;
        iss >> hex >> addr;
        if(!access_counts[addr].count) { // if first time accessing this memory address save the state line
            access_counts[addr].first_line = line;
            access_counts[addr].addr = addr;
            access_count_ptrs.push_back(&access_counts[addr]);
        }
        ++access_counts[addr].count;
    }
    ifs.close();

    // sort access_count_ptrs based on count
    sort(access_count_ptrs.begin(), access_count_ptrs.end(), AccessSort);

    // now print out, max 64k lines (usually max 32k)
    for(AccessCountPtrs::iterator it = access_count_ptrs.begin(); it != access_count_ptrs.end(); ++it) {
        AccessData *ad = *it;
        cout.width(10);
        cout << left << dec << ad->count << ' ' << ad->first_line << endl;
    }
}

by on (#54048)
Quote:
It doesn't seem to be $4018, and $4019 though. When I write them the displayed cyc, ave, and max values don't change. I would appreciate it if you could figure out the right registers. This looks like what I want.


I think it's $401E and $401F.

Quite a handy tool, discovered it a while ago in that thread. Thanks for posting, Memblers.

by on (#54050)
Yeah Miau, those are the ones! Thank you and Memblers and of course Norix! Another question, average seems to be the average of the last frame? That's fine, I'm just making sure. And a request for the good of future people who ask for this, could you (Memblers) throw in a quick readme to your hosted version of this with these registers for future people who might ask for this or find the old topics?

Thefox: A nice idea, actually, but my C/C++ skills are not so good that I'd be able to write a program to parse through the huge files that would be generated quickly. When I was hacking Megaman 3 to contra mode (one hit death) for my friend, I used Nintendulator's logging. For a very small part of gameplay I got a file that was nearly 2 gigabytes. If I was better at C++, I'd try it, or mess with an existing emulator's source code.

For those curious: My worst case scenario is 743 cycles. The average goes as high as in somewhere in the 600s (much worse than I expected). My ideal would be twice as fast. I think and hope I've still got some tricks up my sleeve to make it much faster. Cheers all!