FPS verses millaseconds-per-frame:
As Brother Bob is saying, only gamers measure in FPS, because FPS is almost meaningless. Game developers usually measure the amount of time a frame takes in millaseconds (1/1000th of a second) or in microseconds (1/1,000,000 of a second). At the very least, developers need to understand the difference between FPS and actual frame speeds.
1 FPS = 1000 millaseconds a frame.
2 FPS = 500 millaseconds a frame.
3 FPS = 333 millaseconds a frame.
4 FPS = 250 millaseconds a frame.
10 FPS = 100 millaseconds a frame.
50 FPS = 20 millaseconds a frame.
100 FPS = 10 millaseconds a frame.
FPS is a misleading measurement. It's accurate, but can confuse you if you don't understand how it is measured.
From 1 FPS to 2 FPS is 500 millaseconds more being taken by every frame.
From 50 FPS to 100 FPS is only 10 millaseconds more being taken by every frame.
As Brother Bob said, "A drop from 6000 FPS to 5000 FPS is equivalent to a drop from 60 FPS to ~59.9 FPS". 1000 FPS lost when you are at 6000 FPS, is as small and insignificant as dropping from 60 FPS to 59.9 FPS.
"Economies of scale":
In addition to all the above, it's also good to remember that sometimes doing something (like drawing a sprite) might have alot of one-time setup costs.
Theoretical example: What's the difference between drawing 1 sprite and 5 sprites?
- Bind shader (let's pretend it takes 20 imaginary time units).
- Bind texture (let's pretend it takes 10 ITUs).
- Translate to the location (2 ITUs)
- Render the sprite (3 ITUs)
Total (theoretical) cost: 35 ITUs. Cost per sprite: 35 ITUs.
- Bind shader (20 ITUs)
- Bind texture for sprite A (10 ITUs)
- Translate to location sprite A (2 ITUs)
- Render the sprite A (3 ITUs)
- Sprite A and B share the same texture, so we skip rebinding the texture.
- Translate to the location B (2 ITUs)
- Render the sprite B (3 ITUs)
- Bind texture for sprite C (10 ITUs)
- Translate to sprite location C (2 ITUs)
- Render the sprite C (3 ITUs)
- Bind texture for sprite D (10 ITUs)
- Translate to sprite location D (2 ITUs)
- Render the sprite D (3 ITUs)
- Sprite D and E share the same texture, so we skip rebinding the texture.
- Translate to sprite location E (2 ITUs)
- Render the sprite E (3 ITUs)
Total (theoretical) cost for 5 sprites: 55 ITUs. Cost per sprite 11 ITUs.
When worried about your program's performance:
There's a general rule of thumb programmers have for when looking at the speed of your program: "Don't look at the speed of your program."
Or rather, the actual statement is, "Don't optimize prematurely". Make what you are going to make, and if (when all the fancy numbers are hidden) it noticeably runs too slow, then optimize to make it faster. But if your game runs fine, ignore the numbers, focus on the gameplay. You might even want to hide the numbers (like millasecond framerates and FPS), just so you aren't distracted by them, and only turn the numbers on when it starts to feel too slow. Then you use a profiler and see what parts are actually taking the most time (don't guess - measure with a profiler), then fix those areas.
Also, when worried about performance, make sure you are running in "release mode" rather than "debug mode", because debug mode adds in alot of extra invisible code to help with debugging, that sometimes make your program run slower than it'll actually run when released to users.
tldr: Yes, your program is working fine.