1
\$\begingroup\$

I'm working again on the 3D model of a building in order to parse in JSON every parameters of every objects of the model. My program works well but it is too slow because of the huge number of information : about ~10k objects each containing ~20 parameters. In order to get a lighter JSON we organize it this way :

{
    "Model": { //general information about the 3D model
    },
    "Types" : [ // types relatives parameters
    {
       "Object": { //general information about a specific type (family of objects)
       },
       "Parameters": [ //list of every ID and value of a specific parameter
       ]
    }],
    "Occurrences" : [ // object relatives parameters
    {
        "Object": { //general information about a specific object
        },
        "Parameters": [ //pair of every ID and value of a specific parameter
        ]
    }],
    "DefinitionsTypes": [ // More informations about a type relative parameter 
                          //(name, IsReadOnly...)
    ],
    "DefinitionsObjects": [ //More informations about an occurrences relative parameter
    ]
}

Using StopWatch I know which parts of the code is taking most of the execution time. It is obviously the loop getting parameters on occurrences. Before posting here I try to optimize the code by myself.

  • I replace List I knew the length by arrays
  • I remove useless if and query
  • I replace as much foreach loops by for loops as I could

At the end it comes to a nice result :

  • Execution time from 825 seconds to 333
  • Json file of 129 mO

So the goal is to make it as faster and lighter as possible ! Here is the sample taking most of the time :

for (int i = 0; i < elems.Length; i++) //elems contains every occurrences
            {
                //method to get small amount of information about the
                //occurrence itself (name, ID)
                objectData = JsonObjectData.GetJsonObjectData(elems[i]); 
                //array which contains every parameter of the occurrence 
                // GetOrderedParameters is a method from the Revit API
                Parameter[] paramArray = elems[i].GetOrderedParameters().ToArray();
                for (int j = 0; j < paramArray.Length; j++)
                {
                    // GetJsonDef is a custom method (definition below)
                    objectDefIn.Add(Param.GetJsonDef(paramArray[j]));
                }
                // custom method as well
                parameterData = Param.GetJsonParameterData(elems[i], objectData);
                paramObjectList.Add(parameterData);
            }

GetJsonDef method :

public static ParamDef GetJsonDef(Parameter p)
        {
            //ParamDef is a public struct 
            ParamDef instance = new ParamDef();
            string format = "NoID?";

            if (p.IsShared) //we distinguish shared parameter and builtin
            {
                format = p.GUID.ToString();
                instance = new ParamDef { Name = p.Definition.Name,
                Id = format, UserModifiable = p.UserModifiable,
                IsReadOnly = p.IsReadOnly };
            }
            else
            {
                format = p.Id.ToString();
                instance = new ParamDef { Name = p.Definition.Name,
                Id = format, UserModifiable = p.UserModifiable, 
                IsReadOnly = p.IsReadOnly };
            }

            return instance;

        }

GetJsonParameterData Method :

public static Param GetJsonParameterData
(Element element, JsonObjectData objectData /*Info about the object itself*/)
        {
            // Param is the class (a JsonObjectData and two List of public struct, to distinguish shared parameters)

            Param param = new Param();
            List<ParamList> instance = new List<ParamList>();
            List<ParamList> instanceShared = new List<ParamList>();
            Parameter[] paramArray = element.GetOrderedParameters().ToArray();
            for (int j = 0; j < paramArray.Length; j++)
            {
                if (!paramArray[j].IsShared)
                {
                    string value = paramArray[j].AsValueString();
                    string format = paramArray[j].Id.ToString();
                    ParamList pair = new ParamList { Id = format, Value = value };
                    instance.Add(pair);
                }
                else
                {
                    string value = paramArray[j].AsValueString();
                    string format = paramArray[j].GUID.ToString();
                    ParamList pair = new ParamList { Id = format, Value = value };
                    instanceShared.Add(pair);
                }

            }
            param.Object = objectData;
            param.ObjectParameters = instance;
            param.SharedParameters = instanceShared;
            return param;
        }

Sorry for the long post, I hope it is not too heavy or/and hard to read,

Thank you for your attention anyway !

\$\endgroup\$
1
  • \$\begingroup\$ Initialize your instance and instanceShared lists with paramArray.Length. You'll waste a bit of memory by over provisioning them, but you'll save time by the lists not having to resize as you add elements. Other than that, use a profiler to get more detailed information about where you're spending the time. \$\endgroup\$
    – RobH
    Commented Dec 5, 2016 at 11:55

1 Answer 1

1
\$\begingroup\$

In the GetJsonDef() method, they only difference between the if..elsebranches is the value of the format variable. This format variable can just be initialized to null because you are nevertheless assigning a value to it.

You are assigning a new ParamDef() to the instance variable and later on overwriting it.

This whole method can be simplified to

public static ParamDef GetJsonDef(Parameter p)
{
    string format = null;

    if (p.IsShared) //we distinguish shared parameter and builtin
    {
        format = p.GUID.ToString();
    }
    else
    {
        format = p.Id.ToString();
    }

    return new ParamDef { Name = p.Definition.Name,
    Id = format, UserModifiable = p.UserModifiable,
    IsReadOnly = p.IsReadOnly };

}  

You could use a ternary expression as well instead of the if..else like @eurotrash mentioned in the comment like so

string format = p.IsShared ? p.GUID.ToString() : p.Id.ToString();

in the same way you should change the if..else of the GetJsonParameterData() method.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Could you not reduce further to string format = p.IsShared ? p.GUID.ToString() : p.Id.ToString();? \$\endgroup\$
    – 404
    Commented Dec 5, 2016 at 12:58
  • \$\begingroup\$ @eurotrash good point, edited into the answer. \$\endgroup\$
    – Heslacher
    Commented Dec 5, 2016 at 13:12
  • \$\begingroup\$ Thank you ! The Execution time is now 229 seconds which represent a great improvement ! @RobH I'm gonna try to provide a profiler. Any other ideas are welcome ! \$\endgroup\$
    – Babuh
    Commented Dec 5, 2016 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.