Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameters Take-Up Lots of Program Space #221

Open
LeStarch opened this issue Oct 22, 2020 · 10 comments
Open

Parameters Take-Up Lots of Program Space #221

LeStarch opened this issue Oct 22, 2020 · 10 comments

Comments

@LeStarch
Copy link
Collaborator

Parameters take up a lot of program memory. Can this be reduced?

@nathancheek
Copy link
Contributor

To give some context, I performed a test where I compiled a deployment with no parameters, then added 33 parameters to a single component. This added about 10KB to the program size, or ~300B per parameter. This is a real problem on small embedded platforms such as ATmega and I assume it happens because of all the long-form autocoded functions that are generated for parameters.

I wonder if this code could be modified to take advantage of reusable constructs, rather than writing out the same operation for each parameter. I assume the compiler is having trouble compiling these operations down to reusable instructions, so you end up with a lot of instructions for each parameter.

@LeStarch
Copy link
Collaborator Author

Thanks for filling this in. It is definitely something we should look into.

@ugo94490
Copy link
Contributor

We also checked on our side and found that at each parameter about 350 bytes were added.

So we understand that no fix has been implemented since, do you have a corrective strategy for this problem?

If yes, in which release do you think you can implement it?

For a research project I am prototyping to see if we can modify one of our space flight software to use F Prime.
We have 2Mb of ROM, 4Mb of RAM with 20Kb of parameters (mix of complex structures).
For the unmodified version of the software we have 6% of free memory, so I feel that we are in an unfeasible to fit the application in memory especially because of the exponential size of the parameters formatted in F Prime.

@nathancheek
Copy link
Contributor

How many individual parameters do you have? 20Kb makes me think there are a lot. It might be worth implementing your own parameter handling system in this case.

Do you need parameter persistence (i.e. sending new parameter values that can persist across reboots) or not? The simpler your needs, the more likely you should roll your own solution given that the F Prime autocoded approach still takes up a lot of program memory per parameter. For example, if you don't need persistence, you could try implementing a parameter system using F Prime commands, where the command handler for each component stores incoming parameter values in RAM.

@ThibFrgsGmz
Copy link
Contributor

Just to make sure we understand.

If we want to reload in flight all the parameters spread over a memory area of an arbitrary size of 20Kb we should go through the same system as a complete reload of the flight software or software patch?

That is to say, create a memory write command of n bytes that we send as many times as necessary to cover the entire memory area to be rewritten.
This command would take as parameters the starting memory address (determining whether it is ROM or RAM), the length of the payload to be reloaded and finally n bytes of payload to be written to memory.

@Joshua-Anderson
Copy link
Contributor

@ThibFrgsGmz I think what Nathan is getting at is adding configuration commands to your components. Instead of a parameter FOO, you could add a command called SET_FOO that takes FOO as an argument and sets the FOO variable in your component. Then you can just call SET_FOO before calling anything that uses FOO. This won't persist across reboots, but this would work fine for many use cases, particularly if you're executing command sequences.

@nathancheek
Copy link
Contributor

@Joshua-Anderson Yes this is what I was suggesting. In fact, you could supplement this by specifying initial values for those variables (or the array, if you choose to store this block of data in an array). That would act like the default parameter values you set in the component xml file when using the built-in F Prime parameter system.

@ThibFrgsGmz Given that you have a 20kb block of data you want to load, I could definitely envision a SET_FOO command that takes a starting index and then data, then writes it into that array.

I’m not sure what your use case is, but I’d suggest seeing if you could split the data into related structures, rather than a single array. For example, if you have a list of maximum and minimum temperature thresholds that you want to compare, you could have SET_MAX_TEMP and SET_MIN_TEMP commands which both take in a SENSOR_ID and a TEMPERATURE. The command handler would store the new value in the appropriate array, overwriting the default value you specified in your code. Then you could include private functions or ports GET_MAX_TEMP and GET_MIN_TEMP for reading back the values. Splitting the data out like this might be easier than using a single array for all your parameterized data.

@ThibFrgsGmz
Copy link
Contributor

Thanks for your answers, I get the idea of having a SET_FOO type command. In my use case, it would be if I am providing a platform equipment that needs to be slaved in angular velocity by the AOCS at a certain frequency. In this case, the AOCS would be responsible for updating my angular velocity parameter with this simple command.

Going back to the parameter block issue, on further reflection I could not use this component associated argument functionality for a simple reason.
The idea of having a single block comes from the fact that as unit suppliers of AOCS/GNC system, we don't want to communicate our parameters to the Prime and avoid reverse engineering, well communicate as little as possible. Usually we just give the Prime a formatted binary file that will be uploaded in flight by a memory write command to a specific address. That's why I was saying that we should use a memory patching feature, the same mechanism as for reloading software corrupted by proton flows for example.

But yes it is useful to have a SET_FOO command to update some parameters on the fly when a system operational mode is running. Or even to define operating points for which certain parameter values are defined by mutual agreement with the prime at compile time for example.

@ThibFrgsGmz
Copy link
Contributor

Just out of curiosity, since the autocoder will go entirely through FPP, is this ticket currently being considered in FPP development? Or does FPP replicate the Python autocoder first and then potentially handle this ticket?

@matt392code
Copy link
Contributor

matt392code commented Dec 28, 2024

Potential technical solutions to reduce F Prime's parameter memory footprint

Templated Parameter Handler Architecture:

// Generic parameter handler template
template<typename T>
class ParameterHandler {
public:
    static Fw::ParamValid get(T& val) {
        // Common get logic
    }
    static void set(const T& val) {
        // Common set logic
    }
    static void save() {
        // Common save logic
    }
};

// Parameter instance using shared handler
class MyParam {
private:
    T value;
    ParameterHandler<T>* handler;
public:
    Fw::ParamValid get(T& val) {
        return handler->get(val);
    }
};

Benefits:
*Shared code for common parameter operations
*Reduces code duplication through template specialization
*Maintains type safety while reducing binary size
Parameter Block System:

struct ParameterBlock {
    uint32_t id;
    uint8_t* data;
    size_t size;
    bool modified;
};

class BlockParameterManager {
private:
    vector<ParameterBlock> blocks;
    
public:
    template<typename T>
    T* getParam(uint32_t id) {
        // Locate parameter in appropriate block
        return static_cast<T*>(findBlock(id)->data);
    }
    
    void saveModifiedBlocks() {
        // Save only modified blocks
    }
};

Benefits:
*Groups related parameters into blocks
*Reduces overhead per individual parameter
*More efficient storage and serialization

Command-Based Parameter System:

class ComponentBase {
protected:
    // Shared command handler for parameter updates
    void handleParamCmd(FwOpcodeType opcode, U32 paramId, Fw::CmdStringArg& val) {
        switch(paramId) {
            case PARAM_1:
                updateParam(param1, val);
                break;
            // ...
        }
    }
    
    // Template for parameter updates
    template<typename T>
    void updateParam(T& param, const Fw::CmdStringArg& val) {
        // Common update logic
    }
};

Benefits:
*Leverages existing command system
*Eliminates separate parameter handling code
*More efficient for non-persistent parameters
Memory-Mapped Parameter System:

class MappedParameterManager {
private:
    struct ParamMetadata {
        uint32_t offset;
        uint16_t size;
        uint8_t type;
    };
    
    uint8_t* parameterBlock;
    unordered_map<uint32_t, ParamMetadata> paramMap;
    
public:
    template<typename T>
    T& getParameter(uint32_t id) {
        auto& meta = paramMap[id];
        return *reinterpret_cast<T*>(parameterBlock + meta.offset);
    }
};

Benefits:
*Direct memory access to parameters
*Efficient binary upload/download
*Reduced per-parameter overhead
Hybrid Approach:

class HybridParameterSystem {
private:
    // Fast-access RAM parameters
    BlockParameterManager ramParams;
    
    // Persistent ROM parameters
    MappedParameterManager romParams;
    
    // Shared parameter handlers
    ParameterHandler<int> intHandler;
    ParameterHandler<float> floatHandler;
    
public:
    template<typename T>
    T& getParameter(uint32_t id, ParameterStorage storage) {
        if(storage == RAM) {
            return ramParams.getParam<T>(id);
        } else {
            return romParams.getParameter<T>(id);
        }
    }
};

Benefits:
*Optimizes for different parameter use cases
*Balances memory efficiency with access speed
*Flexible persistence options
Implementation Considerations:
Memory Layout:
*Align parameters to optimize memory access
*Group similar parameters to reduce fragmentation
*Use bit-packing for small parameters
Code Generation:
*Modify autocoder to generate shared handler code
*Use static analysis to optimize parameter grouping
*Generate efficient serialization code
Performance:
*Cache frequently accessed parameters
*Implement lazy loading for rarely used parameters
*Optimize parameter validation code
Safety:
*Maintain parameter validation
*Implement CRC checks for parameter blocks
*Support parameter versioning

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants