Gurobi 9.5 MemLimit usage

Hello everyone,

i am struggeling with the usage of the MemLimit (https://www.gurobi.com/documentation/9.5/refman/memlimit.html) option which was newly introduced in Gurobi 9.5.
Gurobi should throw an error when exceeding the given limit and should not continue solving.
Since this Option needs to be set up in the empty environment this cannot be added via the jump function set_optimizer_attribute.

I found a solution to set the this option like this:

using JuMP, Gurobi

env = Gurobi.Env()
Gurobi.GRBsetdblparam(env, "MemLimit", 1.0)
model = Model(() -> Gurobi.Optimizer(env))

# Set the remaining configurations e.g.:
for (k, v) in Dict("Threads" => 3)
    set_optimizer_attribute(model, k, v)
end

This code snippet should set up a model with a memory limit of 1 GB for the Optimization. But when i am running a more complex optimization which exceeds this limit Gurobi will just continue solving.

Any idea how i can lookup if i set the option correctly?

Thanks in advance.

1 Like

I found out that the attribute is not set correctly by running:

get_optimizer_attribute(model, "MemLimit")
1.0e100

which is the default Gurobi value. I could not find out how to set the attribute correctly by trying multiple variations like GRBsetdblattr, GRBsetintparam, GRBsetintattr…

This should work. Not sure why it doesn’t.

Does this work?

using JuMP, Gurobi
env = Gurobi.Env()
GRBsetdblparam(env, "MemLimit", 1.0)
model = direct_model(Gurobi.Optimizer(env))

(I don’t have Gurobi 9.5 installed, so can’t test.)

1 Like

On Gurobi 9.5, this gives me a return code of 10003 and a message of "Unable to modify parameter MemLimit after environment started".
This is consistent with the documentation linked above:

This parameter must be set when the Gurobi environment is first created. You will need to create an empty environment, set the parameter, and then start the environment.

The best option is to put a file called gurobi.env in the working directory that has contents like:

# Gurobi configuration file
MemLimit 1.0
Threads  8
TimeLimit 600

There is something going on, though, with

since I’ve also observed that

julia> get_optimizer_attribute(model, "MemLimit")
1.0e100

but

julia> x = Ref{Cdouble}();
julia> Gurobi.GRBgetdblparam(env, "MemLimit", x)
0

julia> x[]
1.0

I found a solution. Thanks to @jd-foster I could check if I set the memory limit correctly.
The struggle as you sad is that the environment is already started.

The constructor function in Gurobi would need to be extended to the following for which i already created a pull request in order to set the parameter before the environment is started.

function Env(; output_flag::Int = 1, memory_limit::Number = 1.0e100)
        a = Ref{Ptr{Cvoid}}()
        ret = GRBemptyenv(a)
        env = new(a[], false, 0)
        _check_ret(env, ret)
        ret = GRBsetintparam(env.ptr_env, GRB_INT_PAR_OUTPUTFLAG, output_flag)
        _check_ret(env, ret)
        if _GUROBI_VERSION >= v"9.5.0"
            ret = GRBsetdblparam(env, GRB_DBL_PAR_MEMLIMIT, memory_limit)
            _check_ret(env, ret)
        end
        ret = GRBstartenv(env.ptr_env)
        finalizer(env) do e
            e.finalize_called = true
            if e.attached_models == 0
                # Only finalize the model if there are no models using it.
                GRBfreeenv(e.ptr_env)
                e.ptr_env = C_NULL
            end
        end
        # Even if the loadenv fails, the pointer is still valid.
        _check_ret(env, ret)
        return env
    end

Since we are working on scaling virtual machines where the memory limit should be variable the usage of an environmental file is not really an option. For a workaround until this the memory limit usage is shipped I found the following to work for me:

env = create_gurobi_env(optimizer.Env(); memlimit = 1.0)
model = Model(() -> optimizer.Optimizer(env))

function create_gurobi_env(env::Gurobi.Env; output_flag::Int = 1, memlimit::Number = 1.0e100)
    a = Gurobi.Ref{Ptr{Cvoid}}()
    ret = Gurobi.GRBemptyenv(a)
    env.ptr_env = a[]
    env.finalize_called = false
    env.attached_models = 0
    Gurobi._check_ret(env, ret)
    ret = Gurobi.GRBsetintparam(env.ptr_env, GRB_INT_PAR_OUTPUTFLAG, output_flag)
    Gurobi.GRBsetdblparam(env, GRB_DBL_PAR_MEMLIMIT, memlimit)
    Gurobi._check_ret(env, ret)
    ret = Gurobi.GRBstartenv(env.ptr_env)
    Gurobi.finalizer(env) do e
        e.finalize_called = true
        if e.attached_models == 0
            # Only finalize the model if there are no models using it.
            Gurobi.GRBfreeenv(e.ptr_env)
            e.ptr_env = C_NULL
        end
    end
    # Even if the loadenv fails, the pointer is still valid.
    Gurobi._check_ret(env, ret)
    return env
end

Since the struct Env cannot be created without the constructor function we need to create an environment first and change the struct to a new one which contains the memory limit.

3 Likes

For future reference: https://github.com/jump-dev/Gurobi.jl/pull/465

2 Likes

For future readers, this is fixed in the latest release of Gurobi.jl. Use:

using JuMP, Gurobi
env = Gurobi.Env(memory_limit = 1.0)
model = Model(() -> Gurobi.Optimizer(env))
5 Likes