Блог пользователя E869120

Автор E869120, 7 лет назад, По-английски

Hello Codeforces!

Recently, in JOI 2018 Spring Camp, a young genius QCFium, wrote a naive $$$O(NQ)$$$ algorithm in the problem Examination, and got the perfect score. The code is as follows (Fixed on 2025/5/26):

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
//Naive Solution as follows...

I thought that it was very surprising, but actually, even $$$N,Q \leq 100,000$$$, with the only 3 lines $$$O(NQ)$$$ naive algorithm actually got accepted. To check whether this speedup is actually effective or not, I wrote these two codes: one is with the 3-line speedup, and the other is without the 3-line speedup.

Code A (With speedup)


Code B (Without speedup)


As a result, in custom innovation (code-test) in Codeforces, Code A used 1984ms but Code B used 2561ms. Code A is faster by ~29%. Actually, a young genius QCFium said "The more simple the code is, the more relatively faster with 3-line speedup." So, it could be possible that with speedup, the calculating speed becomes x1.2 or x1.5.

So I have some questions to the community.
Is it possible to use this speedup in CodeForces official contests?
And is it legal to use it in IOI selection contests in your country? (Actually in Japanese Olympiad in Inforcatics, it is OK to use this speedup)

I am very appreciate for sharing your opinion.
Thank you for reading this blog.

  • Проголосовать: нравится
  • +47
  • Проголосовать: не нравится

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

Yes, I've used such pragmas when trying to break some CF problem and it worked. You just need to pay attention to the compiler, since MSVC-specific pragmas don't work on GCC and vice versa (they're simply ignored).

In our IOI selection last year, one guy managed to squeeze some points out of one problem I reused from JOI with looser constraints. It didn't give full score, I think, but it was still quite an impressive speedup and squeezing points like that was in fact one of the expected strategies for those unable to get full score. I imagine most local olympiads don't care — or don't know it matters. Anyway, adding pragmas for AVX and loop unrolling on top of your every code most likely won't slow it down and -O3 is often unnecessary or sometimes even slower than -O2.

  • »
    »
    11 месяцев назад, скрыть # ^ |
     
    Проголосовать: нравится +106 Проголосовать: не нравится

    This post contains wrong pragma code — please learn to use it correctly!

    Sorry for commenting on a 6 years old blog, but this post is the root cause of 10 pages of incorrect pragma usage on google: https://google.com/search?q="pragma+GCC+optimization"

    The pragma snippet provided in the blog contains a typo, it's supposed to be optimize NOT optimization. pajenegod has messaged E869120 about this issue, but no changes has been made.

    Here's the correct snippet:

    #pragma GCC target ("avx2")
    #pragma GCC optimize ("O3")
    #pragma GCC optimize ("unroll-loops")
    

    Please refer to GCC Optimization Pragmas for more details. I'll quote the relevant part here:

    The following does nothing:

    • #pragma GCC optimize(" unroll-loops")
    • #pragma gcc optimize("O3")
    • #pragma GCC optimization("O3")
    • #pragma optimize(O3)

    Yes, these are real-life examples we have seen being used by many competitive programmers, including quite a few LGMs (E.x. 231273727). Perhaps the third one among these came from this post which seems to have popularized the idea of using pragmas, but with a small mistake. Many people are misled to believe that some of the above work, when they actually don't – stop using them.

    Also, #pragma GCC optimize("tune=native") and #pragma GCC optimize("arch=native") do nothing, so that's kinda unfortunate.

    If ever in doubt about whether your pragmas are correct, turn on most compiler warnings with the command-line option -Wall (or the more specific -Wunknown-pragmas). For example, if you compile the code above with -Wall, you'll get the following output, which tells you that the pragmas are invalid and useless:

    foo.cpp:2: warning: ignoring '#pragma gcc optimize' [-Wunknown-pragmas]
        2 | #pragma gcc optimize("O3")
          |
    foo.cpp:3: warning: ignoring '#pragma GCC optimization' [-Wunknown-pragmas]
        3 | #pragma GCC optimization("O3")
          |
    foo.cpp:4: warning: ignoring '#pragma optimize ' [-Wunknown-pragmas]
        4 | #pragma optimize(O3)
          |
    foo.cpp:1:37: warning: bad option '-f unroll-loops' to pragma 'optimize' [-Wpragmas]
        1 | #pragma GCC optimize(" unroll-loops")
          |                                     ^
    

    Try to check if your submissions have similar problems. If yes, then you have probably been using pragmas wrong the entire time — it's time to change your default code.

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +36 Проголосовать: не нравится

We need MrDindows and dmkozyrev here

»
7 лет назад, скрыть # |
Rev. 6  
Проголосовать: нравится +70 Проголосовать: не нравится

This is a short example of x8 speed up for 625 000 000 multiplications of complex numbers: original 3759 ms, 396 kb, improved 187 ms, 400 kb.

I solved a lot of problems (one example), using naive solution in O(n^2) or O(n*q), where q,n <= 200000. Only Ofast, avx, avx2, fma helps a lot (x8 speed up, not so small as x1.2-x1.5), another is not sufficient. AVX for packed floats / doubles, AVX2 for packed integral types, FMA for more effective instructions. When this is enabled, compiler can generate machine-specific code, that allows to work with 256-bit registers by using of avx instructions. But you need to write code in parallel-style with independent iterations of cycles.

You can read a guide to vectorization with intel® c++ compilers. I'm using this too in my everyday work.

UPD. At current time it is a part of GCC/clang compilers, but since C++20 it will be part of standard C++ language. Link, experimental::simd

UPD 2. Increasing of all constraits up to 300-400k will help to drop all such solutions.

  • »
    »
    7 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Your improved 187 ms, 400kb code contains:

    #pragma GCC optimize("Ofast")
    #pragma GCC target("avx,avx2,fma")
    

    which is a bit different from the 3 lines shown in the blog post:

    #pragma GCC target ("avx2")
    #pragma GCC optimization ("O3")
    #pragma GCC optimization ("unroll-loops")
    

    Which one is better to use for speed up the code?

    • »
      »
      »
      7 лет назад, скрыть # ^ |
      Rev. 2  
      Проголосовать: нравится 0 Проголосовать: не нравится

      I think that -Ofast includes all safe and unsafe optimizations for speed up. You can check there. I'm using first, but seems that we need to write unroll-loops too.

      You can compile your source code with next flags: -fopt-info, -fopt-info-loop, -fopt-info-loop-missed, -fopt-info-vec, -fopt-info-vec-missed. Link to all options. It can detect which lines of code have been failed in process of code optimizations and why.

      UPD. I remember that something from list of optimizations allowed me to speed up Segment Tree in 2 times, because it removed tail recursion in recursive queries.

      • »
        »
        »
        »
        6 лет назад, скрыть # ^ |
         
        Проголосовать: нравится 0 Проголосовать: не нравится

        But queries in segment tree uses the result from l to mid and mid + 1 to r and them combine them which is not tail recursion i think(since calling the function is not the last thing done in query function of segment tree). Correct me if i am wrong?

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +9 Проголосовать: не нравится

What does this 3 lines do?? And if i put this pramgas in my code will it speed up?

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

Hi does this work for cms?

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится

Does anyone why does simpler code, make the speedup faster? And also does macros and including bits/stdc++.h instead of iostream for example affect the speedup?

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +13 Проголосовать: не нравится

here is another example where a naive solution can get accepted with pragmas: https://mirror.codeforces.com/contest/911/submission/33820899

vectorization of code can give really big speedups...

»
7 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Is there a way to solve today's Div2B 1143B - Nirvana with this optimization?

»
7 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

To everyone who doesn't know what's going on here: seems that topicstarter doesn't know it either, and it looks like some magic for him.

Better refer to dmkozyrev's message above in the comments.

»
7 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Just to let you folks know, last time I checked it didn't work on USACO. L

»
7 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

Codeforces uses 32-bit binaries (although the servers themselves are 64-bit IIRC), so AVX won't work. Although I'm not completely sure that every language other than C++ also runs in 32-bit mode. If someone found a language running with a 64-bit interpreter, there would be an opportunity for some "bitness arbitrage"...

»
7 лет назад, скрыть # |
 
Проголосовать: нравится +3 Проголосовать: не нравится

will it work only for naive algo ?? because if i am taking simple input and output ..the execution time slows down to 4x .. so what's use of using it ??

  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +14 Проголосовать: не нравится

    Honestly, the main cause of the speedup is called vectorization, which the compiler does automatically due to the pragmas. After blindly trying for some time, I realized that auto-vectorization has very very limited use cases (i.e. it doesn't work most of the time).

    In fact, to truly know how your code has been optimized by the compiler, you need to get down to the assembly code. If you are afraid of the assembly code, stay away from these optimization pragmas and optimize on the algo level only.

»
6 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

This does not work for oj.uz

»
6 лет назад, скрыть # |
Rev. 2  
Проголосовать: нравится +1 Проголосовать: не нравится

Consider using

#pragma GCC target ("native")

To learn about how different compilers do on different architectures with autovectorization, try

https://godbolt.org
  • »
    »
    6 лет назад, скрыть # ^ |
     
    Проголосовать: нравится +3 Проголосовать: не нравится

    If you try to compile with this, you get a compiler error along the lines of attribute(target("native")) is unknown.

    The correct way to specify it in theory would be #pragma GCC target ("arch=native") or #pragma GCC target ("tune=native").

    However, native as architecture isn't recognized in pragmas, see https://stackoverflow.com/a/59846262/1176973. Strangely enough, while tune=native as pragma doesn't trigger an error, it doesn't change the output in any way, whereas -mtune=native as command line argument does.

    So all those tune=native's you can see in some submissions or codebooks (e.g. dacin21_codebook) don't do anything.

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +4 Проголосовать: не нравится

I think it's a good brief explanation about what exactly unroll-loops does.

https://code-examples.net/en/q/17133ec

»
6 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

are there any downfalls for using these optimizations?

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

How to identify which One we have to use??? , there are a lot of optimization So can anyone please explain which one should be use or when?? and is there any general optimization option??

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +8 Проголосовать: не нравится

Most of the online judges seem to ignore pragmas these days.

»
5 лет назад, скрыть # |
 
Проголосовать: нравится -15 Проголосовать: не нравится

Wow!! And I thought JOI Spring Contest was one of the competitions with tightest time limits...

»
5 лет назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

E869120

#pragma 'Optimizations' might slow down your code as well!

NOTE: I don't know much about #pragma, but just wanted to share something I found out while using it.

Compare these two submissions:

Submission 1: #128317329

Submission 2: #128317405

The difference is just that #pragma optimization part is commented out in the accepted submission (#128317405) rest all is same. The one with the 'optimization' got TLE. ;-;

  • »
    »
    5 лет назад, скрыть # ^ |
     
    Проголосовать: нравится 0 Проголосовать: не нравится

    Try to change your compiler to G++17 64-bit. AVX and loops unrolling works much better in the 64-bit mode simply because of a larger number of available registers. Moreover, the 32-bit mode is becoming increasingly more obsolete every year, fewer people are testing the quality of the 32-bit code generated by modern compilers and there may be regressions.

»
11 месяцев назад, скрыть # |
Rev. 2  
Проголосовать: нравится +1 Проголосовать: не нравится

Actually in Syria, I have recently discovered that pragma is not supported but the bad thing is that I discovered it myself and no one told me bofore the contest or even no announcements were made in spite of submitting many codes that uses them in both days which is a very bad thing because the constraints in most problems are very tight (TL and ML) that you might get a solution with the same complexity as intended but do not pass it due to extra work in your code so you need them to pass even non-bruteforce solutions :(. Anyways, is there any other country that does not allow pragma in their national OIs?

»
6 недель назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

These pragmas got me AC on this USACO problem with $$$O(NQ)$$$