Why is moc slow for some classes?



  • Hello,
    I'm currently in the process of optimizing our build time and I figured that moc takes a significant time of our build. While usually, it takes about 0.6 sec for moc to produce moc_* file, for some headers, it takes about 6-10 sec (we have hundreds of such files). Does anyone know what can cause moc to be so slow? Are there any good practices what to avoid in headers parsed by moc?

    The typical file that takes long looks like this:

    #ifndef GUARD
    #define GUARD
    
    namespace a
    {
    
    class Reader : public BaseR<A, B, C>
    {
        using BaseClass = BaseR<A, B, C>;
    public:
        explicit Reader(int);
        X read(const X& x) const;
        Y load() const;
    };
    
    struct Traits
    {
        using A = B;
        using C = D;
        using E = F;
        static const int G = 1;
        static const int ID = 2;
        static const bool B = true;
    };
    
    class Table : public BaseT<Traits>
    {
        Q_OBJECT
        using BaseClass = BaseT<Traits>;
    public:
        Table (A* a, B* b, C* c, D* d);
    protected:
        virtual Type getType() const override { return E_TYPE; }
        virtual B* getReader() const override;
        virtual void createDetails(const A* a, B* b) const override;
    };
    
    }
    #endif
    

    There are about 10 more base classes between BaseT and QObject. Can that be an issue?

    The headers are usually not longer than 50 lines. Can it be the templated base class that causes the problem? Does moc need to instantiate the template?

    Thanks for any help.



  • Hi, can you measure and exclude problems related to hard drive I/O? With hundreds of files (and system doing its stuff in the background) that might be the issue I would try to check first as a possible bottleneck.



  • @Dan-Princ
    not entierly sure, but it might help, to remove the Q_OBJECT Makro in classes where you don't define any new Signals & Slots.



  • @J.Hilk I would advice against. Documentation states:
    Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.



  • @artwaw I have not measured, but the files that are slow are all similar and there are a few thousands other files on the project, which mostly take about 0.5-0.6 sec to parse, so it seems unlikely to be caused by I/O. (and obviously this is reproducible, it's not one time measurement)

    @J.Hilk It is a possibility I'm considering, but we still use some other features of metaObject(), so it would require a little more effort.



  • @Dan-Princ Thanks for clarifying that. My next check would be internal includes, maybe there is a loop somewhere?
    Please note though that I never experienced that kind of problems before and perform a logical guess here.



  • Since I haven't figured out much more about this problem, I removed the Q_OBJECT macro from these classes. Not the best solution, but the only one I know of...


  • Qt Champions 2016

    @Dan-Princ

    Hi
    moc does not expand templates. its not a compiler.

    I tried a few combinations but I could not make moc hang/be slow on any files.

    Do you have a concrete example that compiles and is known to take extra time?



  • @mrjj Unfortunately not, I can't share the code that does it and it's not happening if I try to create some minimal example...


  • Qt Champions 2016

    @Dan-Princ
    ok, i understand.

    I did try with some class with lots of base classes but saw no effect.

    Only by make extremely large .h file i could get time up but it sounds your case
    is different.


  • Moderators

    @Dan-Princ Just an idea: do you include many header files which include other header files and so on?



  • @jsulm Well if I compile the file with /showIncludes, it prints ~3800 includes (mostly from libraries - 2600 from boost, 500 from Qt). If I run preprocessor on the header file, it has about 780000 lines. But I don't know how relevant it is as these numbers will be similar for most of the files I think...


  • Qt Champions 2016

    @Dan-Princ said in Why is moc slow for some classes?:

    • 2600 from boost

    Boost is a template library (mostly) and as any template library is notorious for terrible compilation times, which is a consequence of how templates work.

    it has about 780000 lines

    And you have your answer. That's a huge file to parse.
    And by the way, as @mrjj already said, you can't mix templates and QObject.



  • @kshegunov That's a huge file to parse, true, but there are many other files that have similar (500000) number of lines after preprocessor and moc takes 0.6sec. So I'm not sure this is the main factor.

    You can't put Q_OBJECT inside a template, but AFAIK you can have templated base class.


  • Qt Champions 2016

    @Dan-Princ said in Why is moc slow for some classes?:

    You can't put Q_OBJECT inside a template, but AFAIK you can have templated base class.

    Yes if it doesn't derive from QObject you can do something like:

    class A : public QObject, public MyTemplatedClass< ... > //< QObject derived class always goes first!
    {
    };
    

    But even then it's rather clumsy. QObject doesn't play well with templates.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.