Intel's new 9000 series: i9-9900K, i7-9700K and i5-9600K vs i7-8700K and Ryzen 7 2700X

Intel’s new processors were announced as the fastest gaming processors, and to be also quite fast in other application workloads. Coffee Lake Refresh includes three processors:

  1. The i9-9900K, with 8 cores and 16 threads, currently at $579.99
  2. The i7-9700K, with 8 cores and 8 threads, currently at $409.99
  3. The i5-9600K, with 6 cores and 6 threads, currently at $279.99

All of them reach a high turbo clock: the i9 5.0, the i7 4.9 and the i5 4.6 GHz - without overclocking.

That is a very special release. It’s the first time that Intel releases consumer processors with 8 cores. It’s also the first time Intel releases an i7 without hyperthreading, presumable to give the new i9-9900K a reason to exist. And it’s the first reaction to AMD’s Ryzen processors where Intel had some time to prepare.

Now, we already know the i9-9900k gets hot. But how is the performance? Also the i7-9700K is very interesting this time: Its predecessor, the i7-8700K, had only 6 cores but with 12 threads 4 threads more. Will the missing hyperthreading limit the performance more than the two additional cores and the higher turbo clock can make up for?

Over the last days I gathered reviews for the pc-kombo meta benchmark. The meta benchmark creates a global order out of many distinct smaller benchmarks, currently more than 282. Based on that benchmarks one can not judge how many FPS a processors will reach exactly, but one can judge which processor is faster overall.

Let’s look at gaming performance first:


To see exactly which benchmarks were used, check the comparison page.

The i9-9900K is the fastest gaming processor overall. As the core and thread counts suggest it beats the 9700K. And the i7-9700K beats the former champion, the i7-8700K: Turns out that hyperthreading is less useful than having more cores available. The higher turbo block also won’t hurt this result.

For everyone wanting to use less money it will be nice to know that the i5-9600K stays quite close to the i7-8700K. Since the i7-8700K is not that much slower than the i7-9700K that means that the i5-9600K is still a good option for high FPS gaming, with a similar performance as the i5-8600K. As a result the Ryzen 7 2700X can’t compete here.

However, let’s not forget that the gaming performance of the Ryzen 7 2700X and the Ryzen 5 2600X is still high enough to play all current games properly. It’s just in the high FPS area where Intel was already stronger before this release, and now has a slightly higher lead.

Outside of gaming Intel also reach a very high position with its new processors:


Again, to see exactly which benchmarks were used, check the comparison page.

Finally reaching 8 cores lets Intel overtake the Ryzen 7 2700X in the software performance benchmark, a big win. But the difference is not as big as in gaming, and the smaller chips do not win against the Ryzen processor. Having 16 threads available helps the Ryzen processor against the i7-9700K. And the i5-9600K does not fare well in this benchmarks, though the 9600K did not see many reviews yet and will likely improve later on when more data is added. It should also be noted that software performance is a huge field, and in some applications the performance rating will be more similar to the above gaming performance.

Still, it’s a good result for Intel. The i9-9900K gets a good rating here, and also the i7-9700K does very well. The real stars of this benchmark are processors with an extremely high core count, like the workstation i9 and Threadripper. But this is the best result Intel could have hoped to reach on their consumer platform: Beating the AMD Ryzen 7 2700X on raw performance.

Time for a conclusion. The 9000 series has some issues. Those are hot processors that eat a lot of energy, and they are also very expensive, especially the i9-9900K. But with that i9-9900K Intel for the first time since Ryzen placed a processor on the consumer market that can beat AMD on gaming and multi-threaded application performance, while before Intel only had a lead in gaming. But the i9 is sadly also very expensive, making the Ryzen 7 2700X for many budgets a more attractive option.

The i7-9700K and the i5-9600K are less special. They replace the i7-8700K and the i5-8600K and deliver a small performance improvement, but they do not change the overall situations: Less performance in multi-threaded software workloads than Ryzen, but a better performance in gaming.

As a result, the i9-9900K is the best option currently for those wanting the absolute best performance without making the step to a way more expensive workstation processor, but only for those willing to also buy the best possible cooling hardware and willing to disregard price-performance. The i7-9700K and the i5-9600K can be interchanged with the i7-8700K and the i5-8600K depending on their price, they are best suited for gaming builds targeting 144 FPS. For regular 60Hz gaming (regardless on which resolution) the Ryzen 5 2600X and the Intel Core i5-8400 are still the smarter option, with the Ryzen 5 2600 being a cheaper alternative.

New Intel Core i9 gets very very hot

Intel releasing consumer processors with 8 cores is a big deal, and I know that many gamers were very excited about this release. If the hexa-cores are already stronger than Ryzen, how much better will the new processors be? It turns out not that much, at least in games. But it will take some time till the meta benchmark gets an update, so we will cover this later. For now, let’s look at their temps.

Because it turns out the i7-9700K and especially the i9-9900K get very hot. Hardware Unboxed released a review video showing this graph:


Note that the air cooler reaches 84°C without an overclock, which is very high. And this is not your run of the mill air cooler, the Noctua NH-D15 is right at the top of air cooling performance. As a result, overclocking these processors will basically be impossible, and even without overclocking you need the best cooling money can buy to run them properly.

This is a problem. In the following days we will adapt the hardware recommender to prevent users from accidentally combining these processors with cooler that are too weak for them.


Where Ruby/Sinatra falls short

The PC hardware recommender pc-kombo is written with Ruby and Sinatra, a very comfortable and powerful small framework to build web applications. Web applications is where Ruby shines in general, the language got popular together with the more complete (and opinionated) Ruby on Rails framework.

Sinatra is very nice to work with initially, but over the years it became clear to me that not everything works as good as it should. I’d still recommend it, but would urge beginners to be aware of its limitations.

Some of Sinatra’s issues


1. The routing order matters, and evaluation is not always obvious

That’s stated in the documentation:

Routes are matched in the order they are defined. The first route that matches the request is invoked.

Sounds straightforward, but in practice this gets complicated. As soon as you have routes that match by regexpressions, you won’t always know which order is the correct one. This lead to several situations where we had to shuffle the routes around in our server.rb, where the routes are defined.

Worse: The evaluations order changes over time. Whether it was from Sinatra or Ruby version mismatches, several times everything worked as expected on the dev platform, while as soon as the new routes were added to the production server they covered other, more important routes. Something changed the evaluation order, which lead to frantically searching the right position to define the route. Now imagine not having a classical style Sinatra app, but a modular one.

And a small issue on top of that: If you define /route, /route/ will still throw a 404. The right solution would be to serve the page on the two routes but set one as canonical source. But you have to do that manually.

2. How do you start this thing?

Have a look at the readme. It gives a definite answer on how to start Sinatra:

ruby myapp.rb

Now, isn’t it surprising that this is not how I start my Sinatra application? I have to run

bundle exec puma -e development

The bundle exec is not the fault of Sinatra, that’s just a wrapper to solve dependency management. But the puma -e development should be surprising, as should be that I had to define a That files gets mentioned in the Readme, but what it is for does not get explained.

Sinatra is part of a broader Ruby web ecosystem around the Rack web environment and with influences from Rails. Ever so often parts from there will become relevant to you when you use Sinatra, but if you don’t already know all about Rack and Rails, then you’ll be lost until figuring this ecosystem out.

3. The application webserver story is strong but confusing

So apart from the problem with starting it, what exactly did it start? Sinatra by default can run with multiple application servers. By default is searches for thin, mongrel or webrick, in this order. But maybe you want to run a different server? The start command above shows I use puma. But there is also unicorn, passenger, falcon, and probably many more. It is nice to have many good options, but which one is right for you? Which one can scale the incoming requests properly, ideally over multiple cores?

And besides: If Sinatra starts a server listening for incoming traffic, why does it still seem common to run a regular webserver like nginx in front of that server? Wouldn’t it be better to map port 80 to the application server port with a firewall rule and serve the application directly? Will the url rewriting used in the template understand your setup?

All those questions are not properly answered by the documentation, and you are on your own to find a setup that works for you.

4. There are too many ways to access parameters

The documentation shows this well. There are many ways to react to information given as part of the url or as POST/GET parameter. Let’s count, citing from the Readme again. First there are named parameters, accessible via the params hash:

get '/hello/:name' do
    # matches "GET /hello/foo" and "GET /hello/bar"
    # params['name'] is 'foo' or 'bar'
    "Hello #{params['name']}!"

Or you can put them into a block:

get '/hello/:name' do |n|
    # matches "GET /hello/foo" and "GET /hello/bar"
    # params['name'] is 'foo' or 'bar'
    # n stores params['name']
    "Hello #{n}!"

You can also use wildcards with params['splat']:

get '/say/*/to/*' do
    # matches /say/hello/to/world
    params['splat'] # => ["hello", "world"]

get '/download/*.*' do
    # matches /download/path/to/file.xml
    params['splat'] # => ["path/to/file", "xml"]

Or they can be blocks:

get '/download/*.*' do |path, ext|
    [path, ext] # => ["path/to/file", "xml"]

Or use a regexpression with params['captures']:

get /\/hello\/([\w]+)/ do
    "Hello, #{params['captures'].first}!"

And those can also be blocks:

get %r{/hello/([\w]+)} do |c|
    # Matches "GET /meta/hello/world", "GET /hello/world/1234" etc.
    "Hello, #{c}!"

And that’s not all, there are still optional parameters, and params also contains the regular GET and POST parameters like ?param1=abc&param2=def (by the way: what happens when you send an URL like that as a POST method?). So let’s stop counting here, there is no clear number.

I get that Sinatra wants to be unopinionated and provide several good solutions, but a range of options this broad just leads to chaos.

5. You will need much more than included

Some common scenarios I guarantee you will run into:

  1. HTML-escaping a string in your template
  2. Serving a translated page for visitors from other countries
  3. Rewriting to, or the other way around
  4. Serving your site over https
  5. Redirecting all http:// pages to https://
  6. Running tasks in the background
  7. Saving data in a database, and reading from it

All of that you will have to solve outside of Sinatra, with gems like rack-rewrite (using the from above), picking from Rack::Utils or using sanitize, concepts like threadpools or queues, maybe using additional programs like Redis.

Not all of that is bad: Having to solve database access on your own leads naturally to writing raw SQL, which is often the best solution anyway. But easy problems like escaping HTML get surprisingly hard when your framework does not provide it and you have to figure out how to transport the Rails-centric solutions you find online to your Sinatra program.

6. Which helpers are available anyway?

Sinatra has a lot of useful stuff included, but you have to discover it. And the only place for that seems to be the Readme. This can be slightly problematic. For example: Writing urls in the template often profits from not hardcoding your url, and a gem like url_for can do that. I was still using an external solution way past the moment Sinatra included its own url method, because I was simply not aware of that.

There are solutions for mime types, cache control, redirects, logging, sending files, dealing with dates and some more. And in sinatra-contrib there is some more specialized stuff that will be less often needed. But all that means that you have to think at the right moment to check the Readme, because since not everything is included, sometimes you will miss that a solution to your specific problem is already there.

7. The issue with sessions

Sessions are great, but we ran into overusing them. And there are several per-requisites to make them work. It starts with security:

For better security and usability it’s recommended that you generate a secure random secret and store it in an environment variable on each host running your application so that all of your application instances will share the same secret. You should periodically rotate this session secret to a new value. Here are some examples of how you might create a 64 byte secret and set it

and goes on to realizing you have to use Rack::Session::Pool to be able to store more than the simple values (by storing them on the servers instead of in the visitors cookie). And finally it is being quite complicated to not have multiple session middlewares running by just following the code in the Readme.

There are also not that many alternatives, not many session middlewares you can actually use. There basically is moneta, and while a great project I did not see many reports of the advantages - apart from storing session in a SQL database and thus making them persistent over application restarts while keeping the flexibility of Rack::Session::Pool of what can be stored.

But our main problem was and is overusing sessions. In transporting data via sessions it is too easy to create an application where sharing an url will not lead to the second person seeing the same content on the shared url. That’s why we need a share button to create a permalink after creating a PC build. Now, that’s not really the fault of Sinatra – it’s an architectural issue. But shouldn’t it be the job of the web framework to provide a better alternative? A way to map application content to urls where a part of the url changes with the content? Maybe that is just too specific to pc-kombo, but something to keep in mind when building a similar dynamic application.

8. The built-in protection will block valid access patterns

This was a bad one. Sinatra uses Rack::Protection to prevent a whole bunch of typical attacks. But that way it also blocks valid access patterns, like transporting the jwt access token from the portier authentication system. And then basically the worst case happened in a different project: An early launch that got a lot more publicity than expected with a bunch of visitors not being able to login, because the protection blocked the access token from all visitors using Chrome. Just the most popular browser out there. I had to disable parts of that to make it work, which kind of defeats the purpose of having the protection built in.

9. And finally: Is Ruby the right language for you?

If you start with Sinatra, maybe you do want to start with a cheap server. Who knows whether the new application will earn any money, or maybe earning money is not even the goal. A good way could be a low-power multi-core server like the ones provided by Scaleway, 4 ARM cores for cheap are a good fit for many web applications. Or maybe you know you will get many visitors and want something as efficient as possible.

In that case, at first glance Sinatra is not a bad fit. Compared to Rails it is very lightweight, which has a positive effect on performance.

But the problem might be Ruby. If you use the regular C-Ruby, you use a language that has a very prominent Global Interpreter Lock, and that GIL basically means that your app will be very bad in using multiple small cores. Depending on where you want to deploy your webapp and how many visitors it will serve that might be a problem.

It is still a nice solution

I don’t want to end that article without saying something positive. My true point is: Do not evade Sinatra, but be aware of its shortcomings before starting a project with it.

While the above focuses on Sinatra’s shortcomings, that does not mean that I think it is a bad solution. To the contrary: There are not many web frameworks out there that enable such a nice and fast initial developer experience. With its DSL approach and by providing quite a bunch of solutions to common problems Sinatra is still a great tool for making web apps that work and that can get developed fast. It is even better for just providing an API, or for a very focused web app. It just gets less nice when you realize that the moment you chose Sinatra you also put yourself in a situation where you later will definitely be in uncharted territory.

After you solved those issues once you will have your toolset that covers at least most of those typical issues as well. And you will be more capable for it, regardless with which language and framework you develop your next web application. But till then there will be a lot of uncertainty whether you can succeed with your current Sinatra project at all. And all the time you will find search results showing how to do it in Rails, or with a different more complete framework in a different language.

That’s exciting for some, but not right for every project and not something every developer will want.


Even more gpus for the benchmark

Earlier this month the gpu benchmark got its first set of legacy gpus, the GTX 900 series. Now it got some sets more:

  1. The GeForce 700 series
  2. The GeForce 600 series
  3. The GeForce 500 series
  4. The Radeon Fury series
  5. The Radeon 300 series
  6. The Radeon 200 series
  7. The Radeon HD 7000 series, from the 7970 to the 7750

Lots of care was put into having enough benchmark data available to create a correct order. Whenever a card was not placed in a reasonable position by the algorithm, more benchmarks were added to provide a more accurate picture. That’s especially a challenge when comparing graphics cards from vastly different generations, for example the new GT 1030 with the old Radeon HD 7850 from 2012. Which one would you expect to be faster? The benchmark can answer it now (it’s the 7850).